SETUP FOR OUR PROJECT

### Custom Library
custom_library_path <- "/Users/bonjour/Documents/Master in Economics Bonn/5th semester/Thesis/R-Code/Try with DeSouza Code/Packages"

### Function to check if all required packages are installed and loaded
packageCheck = function(x) {
  # Store original library paths
  original_libpaths <- .libPaths()

  # Set custom library path
  .libPaths(c(custom_library_path, .libPaths()))

  # Check and install package
  if (!require(x, character.only = TRUE, quietly = TRUE)) {
    install.packages(x, dependencies = TRUE, repos = "https://ftp.ussg.iu.edu/CRAN/")
    library(x, character.only = TRUE)
  }

  # Restore original library paths
  .libPaths(original_libpaths)
}

# "bartMachine", "knn", "leekasso", "logreg", "speedlm", "step.interaction", "template", "bayesglm", "caret.rpart", "extraTrees", "glm", "ipredbagg"
# "ksvm", "lm", "mean", "polymars", "rpartPrune", "step", "stepAIC", "cforest", "glm.interaction", "loess", "qda", step.forward", "svm"

## Type in the packages you need below
pkg <- c("SuperLearner", "ggplot2", "RhpcBLASctl","caret", "data.table", "Metrics", "knitr", "kableExtra", "webshot", "processx", "magick", "glmnet", "randomForest", "caret", "earth", "gbm", "nnls", "rpart", "ranger", "biglasso", "gam", "KernelKnn", "lda", "nnet", "ridge", "speedglm")
suppressPackageStartupMessages(lapply(pkg, packageCheck))
[[1]]
[1] "/Library/Frameworks/R.framework/Versions/4.1/Resources/library"

[[2]]
[1] "/Library/Frameworks/R.framework/Versions/4.1/Resources/library"

[[3]]
[1] "/Library/Frameworks/R.framework/Versions/4.1/Resources/library"

[[4]]
[1] "/Library/Frameworks/R.framework/Versions/4.1/Resources/library"

[[5]]
[1] "/Library/Frameworks/R.framework/Versions/4.1/Resources/library"

[[6]]
[1] "/Library/Frameworks/R.framework/Versions/4.1/Resources/library"

[[7]]
[1] "/Library/Frameworks/R.framework/Versions/4.1/Resources/library"

[[8]]
[1] "/Library/Frameworks/R.framework/Versions/4.1/Resources/library"

[[9]]
[1] "/Library/Frameworks/R.framework/Versions/4.1/Resources/library"

[[10]]
[1] "/Library/Frameworks/R.framework/Versions/4.1/Resources/library"

[[11]]
[1] "/Library/Frameworks/R.framework/Versions/4.1/Resources/library"

[[12]]
[1] "/Library/Frameworks/R.framework/Versions/4.1/Resources/library"

[[13]]
[1] "/Library/Frameworks/R.framework/Versions/4.1/Resources/library"

[[14]]
[1] "/Library/Frameworks/R.framework/Versions/4.1/Resources/library"

[[15]]
[1] "/Library/Frameworks/R.framework/Versions/4.1/Resources/library"

[[16]]
[1] "/Library/Frameworks/R.framework/Versions/4.1/Resources/library"

[[17]]
[1] "/Library/Frameworks/R.framework/Versions/4.1/Resources/library"

[[18]]
[1] "/Library/Frameworks/R.framework/Versions/4.1/Resources/library"

[[19]]
[1] "/Library/Frameworks/R.framework/Versions/4.1/Resources/library"

[[20]]
[1] "/Library/Frameworks/R.framework/Versions/4.1/Resources/library"

[[21]]
[1] "/Library/Frameworks/R.framework/Versions/4.1/Resources/library"

[[22]]
[1] "/Library/Frameworks/R.framework/Versions/4.1/Resources/library"

[[23]]
[1] "/Library/Frameworks/R.framework/Versions/4.1/Resources/library"

[[24]]
[1] "/Library/Frameworks/R.framework/Versions/4.1/Resources/library"

[[25]]
[1] "/Library/Frameworks/R.framework/Versions/4.1/Resources/library"

[[26]]
[1] "/Library/Frameworks/R.framework/Versions/4.1/Resources/library"
# Install xgboost
install.packages("xgboost", repos=c("http://dmlc.ml/drat/", getOption("repos")), type="source")
Error in install.packages : Updating loaded packages
# Install PhantomJS which webshot uses
webshot::install_phantomjs()
It seems that the version of `phantomjs` installed is greater than or equal to the requested version.To install the requested version or downgrade to another version, use `force = TRUE`.
# Package for DRDD
remotes::install_github("pedrohcgs/DRDID")
Skipping install of 'DRDID' from a github remote, the SHA1 (8a1c09f9) has not changed since last install.
  Use `force = TRUE` to force installation
# For tables in LATEX code
install.packages("xtable")
Error in install.packages : Updating loaded packages
# Package for graphs
install.packages("dplyr")
Error in install.packages : Updating loaded packages
install.packages("tidyr")
Error in install.packages : Updating loaded packages
install.packages("purrr")
Error in install.packages : Updating loaded packages
# Calling all our packages
library(SuperLearner) # for ML
library(ggplot2) # for graphs
library(RhpcBLASctl)
library(caret)
library(data.table) 
library(Metrics) # for metrics
library(knitr) # for tables
library(kableExtra) # for saving images
library(webshot) # for saving images
library(MASS)
library(magick) # High quality images

# MACHINE LEARNING PACKAGES
library(glmnet) # for ML 1
library(randomForest) # for ML 2
library(xgboost) # for ML 3
#library(bartMachine) # for ML 4
library(caret) # for ML 5
library(earth) # for ML 6
library(gbm) # for ML 7
#library(knn) # for ML 8
#library(leekasso) # for ML 9
#library(logreg) # for ML 10
library(nnls) # for ML 11
library(rpart) # for ML 12
#library(speedlm) # for ML 13
#library(step.interaction) # for ML 14
#library(template) # for ML 15
#library(bayesglm) # for ML 16
#library(caret.rpart) # for ML 17
#library(extraTrees) # for ML 18
#library(glm) # for ML 19
#library(ipredbagg) # for ML 20
#library(ksvm) # for ML 21
#library(lm) # for ML 22
#library(mean) # for ML 23
#library(polymars) # for ML 24
library(ranger) # for ML 25
#library(rpartPrune) # for ML 26
#library(step) # for ML 27
#library(stepAIC) # for ML 28
library(biglasso) # for ML 29
#library(cforest) # for ML 30
library(gam) # for ML 31
#library(glm.interaction) # for ML 32
library(KernelKnn) # for ML 33
library(lda) # for ML 34
#library(loess) # for ML 35
library(nnet) # for ML 36
#library(qda) # for ML 37
library(ridge) # for ML 38
library(speedglm) # for ML 39
#library(step.forward) # for ML 38
#library(svm) # for ML 39


# DRDD
library(DRDID)


# For tables in LATEX code
library(xtable)

# Package for graphs
library(dplyr)
library(purrr)
library(tidyr)

FIRST PART IS CREATING THE SIMULATED DATA BASE

Define the parameters

set.seed(1)

# Parameters

n <- 1000 #individuals
beta.d <- c(0.3, 0.4, 0.5) # beta "d" for 3 different periods
beta.true <- matrix(c(-0.5,0.1,0.5,0.5,-0.5,
                      -0.6,0.2,0.6,0.5,-0.5,
                      -0.8,0.4,0.6,0.9,-0.8,
                      -0.8,0.5,0.7,0.9,-1.0,
                      -0.9,0.7,0.7,1.0,-1.0),nrow= 5, ncol= 5, byrow=TRUE) # betas "X" for 5 different periods
sigma <- matrix(c(1,0.1,0.1,0.1,0.1,
                  0.1,2,0.1,0.1,0.1,
                  0.1,0.1,3,0.1,0.1,
                  0.1,0.1,0.1,4,0.1,
                  0.1,0.1,0.1,0.1,5) ,nrow= 5, ncol= 5, byrow=TRUE) # we will keep the same variance through time
mu <- rep(0,5) # the mean will be zero through time
probability <- 0.5  #

Define the data generating process

# Data generator

data.generator <- function(n, sigma, mu, beta.true, beta.d, probability){
  
  # Xs and errors for 5 periods
  
  # Create an empty list to store the vectors
  x_t_list <- list()
  e_t_list <- list()
  
  # Generate the vectors within the loop and store them in the list with their respective times
  for (i in 1:5) {
    x_ti <- mvrnorm(n, mu, sigma)
    x_t_list[[paste0("x_t", i)]] <- x_ti
    e_ti <- rnorm(n, 0, sqrt(10))
    e_t_list[[paste0("e_t", i)]] <- e_ti
  }

  # Generate the d for 5 periods
  d_t1 <- rep(0, n)
  d_t2 <- rep(0, n)
  d_t3 <- sample(c(0, 1), size = n, replace = TRUE)
  d_t4 <- ifelse(d_t3 == 1 | runif(length(d_t3)) < probability, 1, 0)
  d_t5 <- ifelse(d_t4 == 1 | runif(length(d_t4)) < probability, 1, 0)
  d <- cbind(d_t1, d_t2, d_t3, d_t4, d_t5)
  
  # Generate the ys --------------
  
  # Before treatment
  y_t1 <- x_t_list[["x_t1"]] %*% beta.true[,1] + e_t_list[["e_t1"]]
  y_t2 <- x_t_list[["x_t2"]] %*% beta.true[,2] + e_t_list[["e_t2"]]
  # After treatment
  y_t3 <- d_t3*beta.d[1] + x_t_list[["x_t3"]] %*% beta.true[,3] + e_t_list[["e_t3"]]
  y_t4 <- d_t3*beta.d[2] + x_t_list[["x_t4"]] %*% beta.true[,4] + e_t_list[["e_t4"]]
  y_t5 <- d_t3*beta.d[3] + x_t_list[["x_t5"]] %*% beta.true[,5] + e_t_list[["e_t5"]]
  y <- cbind(y_t1, y_t2, y_t3, y_t4, y_t5)
  
  #Standardize Xs
  
  # Initialize the list to store standardized matrices
  x_t_list.sd <- list()
  
  for (variable in names(x_t_list)) {
    #Defining the matrices
    x_t_list.sd[[paste0(variable, ".sd")]] <- matrix(NA, nrow = nrow(x_t_list[[variable]]), ncol = ncol(x_t_list[[variable]]))
    #Starting the standardization
    for (i in 1:ncol(x_t_list.sd[[paste0(variable, ".sd")]])){
    x_t_list.sd[[paste0(variable, ".sd")]][, i] <- (x_t_list[[variable]][, i] - mean(x_t_list[[variable]][, i])) / sd(x_t_list[[variable]][, i])
    }
  }
  
  data <- data.frame ("y" = y, "d" = d, "x" = x_t_list, "x.sd" = x_t_list.sd)
  return(data)
}

Generate the data set

# We can make generate a data set
MyData <- data.generator(n, sigma, mu, beta.true, beta.d, probability)

ADVANCED FUNCTION TO RECOVER THE ATT, MAE, MSE, R2 AND THE DENSITIES - MACHINE LEARNING

Function

ATT_ML_generator_ADVANCED <- function(MyData, CV_num_folds, starting_test_period, ending_test_period, models, models_names){

# This vector will store my densities
densities_list <- list()

# To store the y densities
densities_y <- list()

# Define the model names actual value
models_names_act <- c(models_names, "JointM")

# Define lists
MAE <- list()
MSE <- list()
R2 <- list()
ATT <- list()

# Complete data for periods 3 - 5

for (i in starting_test_period:ending_test_period){
  
  # Create variable names based on the loop index
  x_prefix <- paste("x.x_t", i, sep = "")
  d_prefix <- paste("d.d_t", i, sep = "")
  y_prefix <- paste("y.", i, sep = "")
  Data_completeX_prefix <- paste("Data_complete_Xt", i, sep = "")
  Data_completeY_prefix <- paste("Data_complete_Yt", i, sep = "")
  
  # Complete the one for X
  x_variables <- paste(x_prefix, 1:5, sep = ".")
  
  # Subset the data based on the constructed variable names
  subset_data_x <- subset(MyData, select = c(d_prefix, x_variables))
  assign(Data_completeX_prefix, as.data.frame(subset_data_x)) # X as dataframe
  
  # Subset and assign Y
  assign(Data_completeY_prefix, MyData[[y_prefix]]) # Y
  
  # Now let's get the actual values of Data_completeX_prefix and Data_completeY_prefix for later usage
  Data_completeX_actual <- get(Data_completeX_prefix)
  Data_completeY_actual <- get(Data_completeY_prefix)
  
  # Let's also get the density fo Actual Y just for later -----
  
  # Create the variable for the density
  Y_Density_Complete <- paste("Density_", Data_completeY_prefix, sep = "")
  
  # Assign the values of the variables
  assign(Y_Density_Complete, density(Data_completeY_actual))
  
  # Store the values for usage inside the loop of the Y density
  Y_density <- get(Y_Density_Complete)
  
  # TRAIN DATA FOR ALL PERIODS--------------------------------------------------
  
  # Data to Train
  Data_toTrain_prefix <- paste("Data_toTrain_t", i, sep = "")
  
  # Create variable names based on the loop index
  Train_x_prefix <- paste("Train_x_t", i, sep = "")
  Train_y_prefix <- paste("Train_y_t", i, sep = "")
  
  # Subset the data based on the constructed variable names
  Data_toTrain_subset <- subset(MyData, MyData[[d_prefix]] == 0)
  assign(Data_toTrain_prefix, Data_toTrain_subset) # Data to train
  assign(Train_x_prefix, as.data.frame(subset(Data_toTrain_subset, select = c(d_prefix, x_variables)))) # X
  assign(Train_y_prefix, Data_toTrain_subset[[y_prefix]]) # Y
  
  # HOLD DATA FOR ALL PERIODS---------------------------------------------------
  
  # Data to Train
  Data_toHold_prefix <- paste("Data_toHold_t", i, sep = "")
  
  # Create variable names based on the loop index
  Hold_x_prefix <- paste("Hold_x_t", i, sep = "")
  Hold_y_prefix <- paste("Hold_y_t", i, sep = "")
  
  # Subset the data based on the constructed variable names
  Data_toHold_subset <- subset(MyData, MyData[[d_prefix]] == 1)
  assign(Data_toHold_prefix, Data_toHold_subset) # Data to hold
  assign(Hold_x_prefix, as.data.frame(subset(Data_toHold_subset, select = c(d_prefix, x_variables)))) # X
  assign(Hold_y_prefix, Data_toHold_subset[[y_prefix]]) # Y
  
  # LET'S USE OUR MACHINE LEARNING MODELS --------------------------------------
  
  ## Define the number of subdata splits for the Cross-Validation
  control <- SuperLearner.CV.control(V = CV_num_folds)

   # Define the vector that will store my models
  models_use <- c() # empty by now
  
  # Then the loop 
  for (j in seq_along(models)) {
    
      # Create the variables names
      model_name_prefix <- paste(models_names[j], "_t", i, sep = "")

      # Set the seed
      set.seed(1)
      
      # Use the model name in the SuperLearner function
      assign(model_name_prefix, SuperLearner(Y = get(Train_y_prefix), X = get(Train_x_prefix), family = gaussian(), SL.library = models[j], cvControl = control))
      
      # Add elements top the models_use
      models_use <- c(models_use, model_name_prefix)
  }
  
  # Defining the joint model
  JointM_prefix <- paste("JointM_t", i, sep = "")
   # Set the seed
  set.seed(1)
  # Joint model
  assign(JointM_prefix, SuperLearner(Y = get(Train_y_prefix), X = get(Train_x_prefix), family = gaussian(), SL.library = models, cvControl = control))
  
  # Add last element to models_use
  models_use <- c(models_use, JointM_prefix)
  
  # UNTIL HERE ALL FINE --------------------------------------------------------------------------------------------------------------------
  
  # PREDICTIONS TIME -------------------------------------------------------------------------------------------------------
  
  # Initialize the inner list for models for the current period
  MAE_period <- list()
  MSE_period <- list()
  R2_period <- list()
  ATT_period <- list()

  for (model in models_use) {
    
    # Extracting the actual object (for both PRE- and POST- treatment predictions)
    model_obj <- get(model)
    
    # PRE-TREATMENT PREDICTIONS---------------------------
  
    # Create variable names based on the loop index
    in_preds_model_pre_prefix <- paste("in_preds_", model, "_pre", sep = "")
    cv_preds_model_pre_prefix <- paste("in_preds_", model, "_pre", sep = "")
    data_model_pre_prefix <- paste("data_", model, "_pre", sep = "")
  
    # Assign the values
    assign(in_preds_model_pre_prefix, as.data.frame(model_obj$library.predict))
    assign(cv_preds_model_pre_prefix, as.data.frame(model_obj$Z))
  
    # Change the columns names
    original_in_preds_model <- get(in_preds_model_pre_prefix)
    colnames(original_in_preds_model) <- sprintf('%s_in_%s', model, colnames(original_in_preds_model))
    assign(in_preds_model_pre_prefix, original_in_preds_model)

    original_cv_preds_model <- get(cv_preds_model_pre_prefix)
    colnames(original_cv_preds_model) <- sprintf('%s_cv_%s', model, colnames(original_cv_preds_model))
    assign(cv_preds_model_pre_prefix, original_cv_preds_model)
  
    # Joining both variables into a dataframe
    assign(data_model_pre_prefix, cbind(get(in_preds_model_pre_prefix), get(cv_preds_model_pre_prefix)))
    
    
    # LET'S RECOVER THE CROSSVALIDATED ERRORS-----
    
    # Create variable names based on the loop index
    CV_names <- paste("CV_E_", model, sep = "")
    
    # Assign the values 
    assign(CV_names, get(Train_y_prefix) - get(cv_preds_model_pre_prefix))
    
    # POST-TREATMENT PREDICTIONS-------------------------
    
    # Create variable names based on the loop index
    preds_model_post_prefix <- paste("predModel_", model, "_post", sep = "")
    data_model_post_prefix <- paste("data_", model, "_post", sep = "")
    
    # Assign the values
    assign(preds_model_post_prefix, predict(model_obj, Data_completeX_actual, onlySL = T))
    
    # Now get the preds_model_post_prefix actual value
    preds_model_obj <- get(preds_model_post_prefix) # Also needed for the subsequent steps
    
    # Assign the values now
    assign(data_model_post_prefix, as.data.frame(preds_model_obj$pred))
    
    # Change the columns names
    original_data_model_post <- get(data_model_post_prefix)
    colnames(original_data_model_post) <- sprintf('%s_in_%s', model, colnames(original_data_model_post))
    assign(data_model_post_prefix, original_data_model_post)
    
    # -----------------------------------------------------------------------------------------------------
    
    # LET'S GET THE DENSITIES FOR PLOTTING------
    
    # Create variable names based on the loop index
    Density_name <- paste("density_", model, sep = "")
    
    # Assign the values
    # assign(Density_name, data_model_post_prefix[, 1]) # This will return the value as a vector
    assign(Density_name, density(preds_model_obj$pred[, 1])) # This will return the value as a vector, using preds_model_obj OBJECT
    
    # -----------------------------------------------------------------------------------------------------
    
    # LET'S GET THE MAE, MSE & R2
    
    # We will use, MAE (mean absolute error), MSE (mean squared error, this one makes sure to deal with negative distances), R2 (R-squared)

    # Compute MAE, MSE & R2 for the current model and period
    MAE_value <- mae(Data_completeY_actual, as.vector(unlist(get(data_model_post_prefix))))
    MSE_value <- mse(Data_completeY_actual, as.vector(unlist(get(data_model_post_prefix))))
    R2_value <- R2(Data_completeY_actual, as.vector(unlist(get(data_model_post_prefix))))

    # Store the MAE, MSE, R2 value in the respective list based on the model type THS FOR EACH
    
    # Store the MAE value in the inner list for the current model
    MAE_period[[model]] <- MAE_value
    
    # Store the MAE value in the inner list for the current model
    MSE_period[[model]] <- MSE_value
    
    # Store the MAE value in the inner list for the current model
    R2_period[[model]] <- R2_value

    # -----------------------------------------------------------------------------------------------------
    
    # LET'S GET THE DIFFERENCES THAT WE WILL NEED TO RECOVER THE ATT
    
    # Create variable names based on the loop index
    Differences <- paste("Difference_", model, sep = "")
    
    # Assign the values now
    assign(Differences, as.vector(unlist(get(data_model_post_prefix))) - Data_completeY_actual)
    
    # -----------------------------------------------------------------------------------------------------
    
    # LET'S GET ATT PER PERIOD PER MODEL
    
    # Create variable names based on the loop index
    # ATT <- paste("ATT_", model, sep = "") # ACTUALLY NO NEED
    
    # Compute ATT for the current model and period
    ATT_value <- mean(get(paste("Difference_", model, sep = "")))
    
    # Store the MAE value in the inner list for the current model
    ATT_period[[model]] <- ATT_value
    
  }
  
  # MAE, MSE, R2 & ATT -------------------------------------------------------------------------------------------------
  # Append the inner list to the outer list for the current period
  MAE[[paste("Period", i, sep = "_")]] <- MAE_period
  MSE[[paste("Period", i, sep = "_")]] <- MSE_period
  R2[[paste("Period", i, sep = "_")]] <- R2_period
  ATT[[paste("Period", i, sep = "_")]] <- ATT_period
  
  # Densities -----------------------------------------------------------------------------------------------------------
  
  # Create variable names based on the loop index
  Data_plotting <- paste("ToPlotData_densities_t", i, sep = "")

  # Get the values of the models again - Using the fact that we have already defined our models above in "models_use" outside the model loop
  Y_actual_density <- get(paste("Density_", Data_completeY_prefix, sep = ""))
  
  # Period densities
  period_densities <- list()
  
  for (m in seq_along(models_use)) {
    
    # Defining the names of the densities
    model_name <- models_names_act[m] # To define the name of the model
    prefix_density <- paste(model_name, "density", sep = "_")
    
    # Defining the values to be assigned
    model_values <- get(paste("density_", models_use[m], sep = ""))

    # Create variable names dynamically
    assign(prefix_density, model_values)
    
    # Store the densities
    period_densities[[prefix_density]] <- get(prefix_density)
    
  }

  # List of models
  list_models <- c("Y_actual", "LASSO", "Random Forest", "XGBoost", "JointM")
  
  # Store my densities
  
  # Defining variable names inside the list
  names_densities_periods <- paste("t", i, sep = "")
  densities_list[[names_densities_periods]] <- period_densities
  
  # Adding the value of Y density------------------------------------------------------
  densities_y[[paste("Density_yt", i, sep = "")]] <- Y_actual_density

}

# Statistics 

# Combine the vectors into a list
Statitics <- list(
  ATT = ATT,
  MAE = MAE,
  MSE = MSE,
  R2 = R2
)

# AVERAGES---------------------------------------------------------------------------------------------------------------------------------

# Now depending on the number of periods and the number of models so we need to divide for exampel if models are
num_periods = (ending_test_period - starting_test_period) + 1
num_models = length(models_names_act)

# Averages per model
Statistic_averages <- list()

# Statistics list
Statistics_list <- c("ATT", "MAE", "MSE", "R2")

# Loop over Statistics list
for (s in Statistics_list) {
  
  # List averages
  Averages_list <- list()
  
  # Loop over models
  for (mod in models_names_act) {
  
    # Create the name of the variable
    Prefix_average <- paste(s, mod, "average", sep = "_")

    # Initialize mean_per_model for each model
    mean_per_model <- 0

    # Loop over periods
    for (i in 1:num_periods) {
      # Collecting the mean for each model for each period
      stat_value <- get(paste(s, sep = ""))[[i]][[which(models_names_act == mod)]]
      mean_per_model <- mean_per_model + stat_value
    }

    # Calculate the average across all periods for the current model
    mean_per_model <- mean_per_model / num_periods

    # Store the result in Averages_list
    Averages_list[[Prefix_average]] <- mean_per_model
  }
  
  # Store the values
  Statistic_averages[[s]] <- Averages_list
}


################################ ACTUAL OUTPUTS ##############################################

output <- list(
  FitnessStatistics = Statitics,
  average_values = Statistic_averages,
  densities_y = densities_y,
  densities_ML_list = densities_list
)

return(output)

}

ADVANCED FUNCTION TO RECOVER THE ATT, MAE, MSE, R2 AND THE DENSITIES - DRDD

DRDD_RESULTS <- function(MyData, starting_test_period, ending_test_period){
  
# INPUTS
# MyData = MyData
# starting_test_period = 3
# ending_test_period = 5

# This vector will store my different regression values
DRDD_list <- list()
  
  for (i in starting_test_period:ending_test_period) {
    
    # Subset MyData based on the condition d.d_t_i-1 == 0, just for the people that in the previous period were not treated
    MyData <- MyData[MyData[[paste("d.d_t", i-1, sep = "")]] == 0, ]
    
    # DDRD values
    DDRD_value <- drdid_imp_panel(y1 = MyData[[paste("y", i , sep = ".")]], y0 = MyData[[paste("y", i-1 , sep = ".")]],
                D = MyData[[paste("d.d_t", i , sep = "")]],
                covariates = cbind(MyData[[paste("x.x_t", i, ".1", sep = "")]], MyData[[paste("x.x_t", i, ".2", sep = "")]], MyData[[paste("x.x_t", i, ".3", sep = "")]], MyData[[paste("x.x_t", i, ".4", sep = "")]], MyData[[paste("x.x_t", i, ".5", sep = "")]]))

    # Add them to the list
    DRDD_list[[paste("DRDD_t", i, sep = "")]] <- DDRD_value
  }


# Result my list
return(DRDD_list)  

}

NOW LET’S SHOW OUR RESULTS

INPUTS

MyData = MyData # or whichever data you have
CV_num_folds = 10 # or whatever may be decided
starting_test_period = 3 # can be adapted depending on the starting treatment period of your database
ending_test_period = 5 # can be adapted depending on the ending treatment period of your database
models <- c("SL.glmnet", "SL.randomForest", "SL.xgboost", "SL.kernelKnn") # can be adapted given the models that you will be using
models_names <- c("LASSO", "RF", "XgB", "KernelKnn") # can be adapted given the models that you will be using

1) MACHINE LEARNING

Results of the function

ML_RESULTS_SEVERAL <- ATT_ML_generator_ADVANCED(MyData, CV_num_folds, starting_test_period, ending_test_period, models, models_names)

GRAPHS AND MAIN RESULTS OF THE FUNCTION

ATT

# Transform the ATT list into a data frame
ATT_df <- data.frame(matrix(unlist(ML_RESULTS_SEVERAL$FitnessStatistics$ATT), nrow = length(ML_RESULTS_SEVERAL$FitnessStatistics$ATT), byrow = TRUE), row.names = names(ML_RESULTS_SEVERAL$FitnessStatistics$ATT))

# We will also use the averages lists for our purposes
ATT_averages <- data.frame(matrix(unlist(ML_RESULTS_SEVERAL$average_values$ATT), nrow = length(ML_RESULTS_SEVERAL$average_values$ATT), byrow = TRUE), row.names = names(ML_RESULTS_SEVERAL$average_values$ATT))

# Bind both of the just dataframes
ATT_forTable <- cbind(t(ATT_df), ATT_averages)

# Add column names
colnames(ATT_forTable) <- c("t3", "t4", "t5", "average") 

# Add row names
rownames(ATT_forTable) <- c(models_names, "JointM")

# Create a code for a LaTeX Table
latex_code_ATT <- xtable(ATT_forTable, caption = "ML ATT per model per period estimated")

# Print the LaTeX code
print(latex_code_ATT, include.rownames = T)
% latex table generated in R 4.1.1 by xtable 1.8-4 package
% Wed Mar  6 19:54:16 2024
\begin{table}[ht]
\centering
\begin{tabular}{rrrrr}
  \hline
 & t3 & t4 & t5 & average \\ 
  \hline
LASSO & -0.20 & -0.69 & -0.43 & -0.44 \\ 
  RF & -0.20 & -0.79 & -0.42 & -0.47 \\ 
  XgB & -0.16 & -0.82 & -0.35 & -0.45 \\ 
  KernelKnn & -0.23 & -0.83 & -0.63 & -0.56 \\ 
  JointM & -0.20 & -0.69 & -0.43 & -0.44 \\ 
   \hline
\end{tabular}
\caption{ML ATT per model per period estimated} 
\end{table}

MAE

# Transform the ATT list into a data frame
MAE_df <- data.frame(matrix(unlist(ML_RESULTS_SEVERAL$FitnessStatistics$MAE), nrow = length(ML_RESULTS_SEVERAL$FitnessStatistics$MAE), byrow = TRUE), row.names = names(ML_RESULTS_SEVERAL$FitnessStatistics$MAE))

# We will also use the averages lists for our purposes
MAE_averages <- data.frame(matrix(unlist(ML_RESULTS_SEVERAL$average_values$MAE), nrow = length(ML_RESULTS_SEVERAL$average_values$MAE), byrow = TRUE), row.names = names(ML_RESULTS_SEVERAL$average_values$MAE))

# Bind both of the just dataframes
MAE_forTable <- cbind(t(MAE_df), MAE_averages)

# Add column names
colnames(MAE_forTable) <- c("t3", "t4", "t5", "average") 

# Add row names
rownames(MAE_forTable) <- c(models_names, "JointM")

# Create a code for a LaTeX Table
latex_code_MAE <- xtable(MAE_forTable, caption = "ML MAE per model per period estimated")

# Print the LaTeX code
print(latex_code_MAE, include.rownames = T)
% latex table generated in R 4.1.1 by xtable 1.8-4 package
% Wed Mar  6 19:54:19 2024
\begin{table}[ht]
\centering
\begin{tabular}{rrrrr}
  \hline
 & t3 & t4 & t5 & average \\ 
  \hline
LASSO & 2.59 & 2.64 & 2.60 & 2.61 \\ 
  RF & 2.00 & 2.49 & 2.64 & 2.38 \\ 
  XgB & 1.66 & 2.44 & 2.86 & 2.32 \\ 
  KernelKnn & 2.72 & 2.83 & 2.89 & 2.81 \\ 
  JointM & 2.53 & 2.64 & 2.60 & 2.59 \\ 
   \hline
\end{tabular}
\caption{ML MAE per model per period estimated} 
\end{table}

MSE

# Transform the ATT list into a data frame
MSE_df <- data.frame(matrix(unlist(ML_RESULTS_SEVERAL$FitnessStatistics$MSE), nrow = length(ML_RESULTS_SEVERAL$FitnessStatistics$MSE), byrow = TRUE), row.names = names(ML_RESULTS_SEVERAL$FitnessStatistics$MSE))

# We will also use the averages lists for our purposes
MSE_averages <- data.frame(matrix(unlist(ML_RESULTS_SEVERAL$average_values$MSE), nrow = length(ML_RESULTS_SEVERAL$average_values$MSE), byrow = TRUE), row.names = names(ML_RESULTS_SEVERAL$average_values$MSE))

# Bind both of the just dataframes
MSE_forTable <- cbind(t(MSE_df), MSE_averages)

# Add column names
colnames(MSE_forTable) <- c("t3", "t4", "t5", "average") 

# Add row names
rownames(MSE_forTable) <- c(models_names, "JointM")

# Create a code for a LaTeX Table
latex_code_MSE <- xtable(MSE_forTable, caption = "ML MSE per model per period estimated")

# Print the LaTeX code
print(latex_code_MSE, include.rownames = T)
% latex table generated in R 4.1.1 by xtable 1.8-4 package
% Wed Mar  6 19:54:22 2024
\begin{table}[ht]
\centering
\begin{tabular}{rrrrr}
  \hline
 & t3 & t4 & t5 & average \\ 
  \hline
LASSO & 10.53 & 10.85 & 10.66 & 10.68 \\ 
  RF & 7.14 & 10.48 & 11.30 & 9.64 \\ 
  XgB & 7.87 & 11.85 & 14.56 & 11.43 \\ 
  KernelKnn & 11.68 & 12.42 & 13.04 & 12.38 \\ 
  JointM & 10.00 & 10.85 & 10.66 & 10.50 \\ 
   \hline
\end{tabular}
\caption{ML MSE per model per period estimated} 
\end{table}

R2

# Transform the ATT list into a data frame
R2_df <- data.frame(matrix(unlist(ML_RESULTS_SEVERAL$FitnessStatistics$R2), nrow = length(ML_RESULTS_SEVERAL$FitnessStatistics$R2), byrow = TRUE), row.names = names(ML_RESULTS_SEVERAL$FitnessStatistics$R2))

# We will also use the averages lists for our purposes
R2_averages <- data.frame(matrix(unlist(ML_RESULTS_SEVERAL$average_values$R2), nrow = length(ML_RESULTS_SEVERAL$average_values$R2), byrow = TRUE), row.names = names(ML_RESULTS_SEVERAL$average_values$R2))

# Bind both of the just dataframes
R2_forTable <- cbind(t(R2_df), R2_averages)

# Add column names
colnames(R2_forTable) <- c("t3", "t4", "t5", "average") 

# Add row names
rownames(R2_forTable) <- c(models_names, "JointM")

# Create a code for a LaTeX Table
latex_code_R2 <- xtable(R2_forTable, caption = "ML R2 per model per period estimated")

# Print the LaTeX code
print(latex_code_R2, include.rownames = T)
% latex table generated in R 4.1.1 by xtable 1.8-4 package
% Wed Mar  6 19:54:26 2024
\begin{table}[ht]
\centering
\begin{tabular}{rrrrr}
  \hline
 & t3 & t4 & t5 & average \\ 
  \hline
LASSO & 0.41 & 0.55 & 0.54 & 0.50 \\ 
  RF & 0.63 & 0.60 & 0.53 & 0.58 \\ 
  XgB & 0.57 & 0.54 & 0.43 & 0.51 \\ 
  KernelKnn & 0.35 & 0.51 & 0.46 & 0.44 \\ 
  JointM & 0.44 & 0.55 & 0.54 & 0.51 \\ 
   \hline
\end{tabular}
\caption{ML R2 per model per period estimated} 
\end{table}

Densities

list_models <- c("Y_actual", models_names, "JointM")

3rd period

# Values of the densities
ToPlotData_densities_t3 <- data.frame(
  value = c(ML_RESULTS_SEVERAL$densities_y$Density_yt3$x, 
            ML_RESULTS_SEVERAL$densities_ML_list$t3$LASSO_density$x, 
            ML_RESULTS_SEVERAL$densities_ML_list$t3$RF_density$x, 
            ML_RESULTS_SEVERAL$densities_ML_list$t3$XgB_density$x,
            ML_RESULTS_SEVERAL$densities_ML_list$t3$KernelKnn_density$x,
            ML_RESULTS_SEVERAL$densities_ML_list$t3$JointM_density$x),
  density = c(ML_RESULTS_SEVERAL$densities_y$Density_yt3$y, 
            ML_RESULTS_SEVERAL$densities_ML_list$t3$LASSO_density$y, 
            ML_RESULTS_SEVERAL$densities_ML_list$t3$RF_density$y, 
            ML_RESULTS_SEVERAL$densities_ML_list$t3$XgB_density$y,
            ML_RESULTS_SEVERAL$densities_ML_list$t3$KernelKnn_density$y,
            ML_RESULTS_SEVERAL$densities_ML_list$t3$JointM_density$y),
  model = factor(rep(list_models, times = sapply(list(
    ML_RESULTS_SEVERAL$densities_y$Density_yt3,
    ML_RESULTS_SEVERAL$densities_ML_list$t3$LASSO_density, 
    ML_RESULTS_SEVERAL$densities_ML_list$t3$RF_density, 
    ML_RESULTS_SEVERAL$densities_ML_list$t3$XgB_density,
    ML_RESULTS_SEVERAL$densities_ML_list$t3$KernelKnn_density,
    ML_RESULTS_SEVERAL$densities_ML_list$t3$JointM_density
  ), function(d) length(d$x))))
)

# Plot superimposed density curves
ggplot(ToPlotData_densities_t3, aes(x = value, y = density, color = model)) +
  geom_line(linewidth = 0.25) +
  theme_minimal() +
  labs(title = "Density of the different models period 3", x = "Values", y = "Density") +
  scale_color_discrete(name = "Model")

# Define the path for the PNG image
Densities_t3 <- "/Users/bonjour/Documents/Master in Economics Bonn/5th semester/Thesis/R-Code/Drafts/11th Draft - Advanced function and Montecarlo/Images/Densities_t3.png"

# Save the ggplot as a PNG image
ggsave(filename = Densities_t3, plot = last_plot(), width = 6, height = 4, dpi = 300)

4th period

# Values of the densities
ToPlotData_densities_t4 <- data.frame(
  value = c(ML_RESULTS_SEVERAL$densities_y$Density_yt4$x, 
            ML_RESULTS_SEVERAL$densities_ML_list$t4$LASSO_density$x, 
            ML_RESULTS_SEVERAL$densities_ML_list$t4$RF_density$x, 
            ML_RESULTS_SEVERAL$densities_ML_list$t4$XgB_density$x,
            ML_RESULTS_SEVERAL$densities_ML_list$t4$KernelKnn_density$x,
            ML_RESULTS_SEVERAL$densities_ML_list$t4$JointM_density$x),
  density = c(ML_RESULTS_SEVERAL$densities_y$Density_yt4$y, 
            ML_RESULTS_SEVERAL$densities_ML_list$t4$LASSO_density$y, 
            ML_RESULTS_SEVERAL$densities_ML_list$t4$RF_density$y, 
            ML_RESULTS_SEVERAL$densities_ML_list$t4$XgB_density$y,
            ML_RESULTS_SEVERAL$densities_ML_list$t4$KernelKnn_density$y,
            ML_RESULTS_SEVERAL$densities_ML_list$t4$JointM_density$y),
  model = factor(rep(list_models, times = sapply(list(
    ML_RESULTS_SEVERAL$densities_y$Density_yt4,
    ML_RESULTS_SEVERAL$densities_ML_list$t4$LASSO_density, 
    ML_RESULTS_SEVERAL$densities_ML_list$t4$RF_density, 
    ML_RESULTS_SEVERAL$densities_ML_list$t4$XgB_density,
    ML_RESULTS_SEVERAL$densities_ML_list$t4$KernelKnn_density,
    ML_RESULTS_SEVERAL$densities_ML_list$t4$JointM_density
  ), function(d) length(d$x))))
)

# Plot superimposed density curves
ggplot(ToPlotData_densities_t4, aes(x = value, y = density, color = model)) +
  geom_line(linewidth = 0.25) +
  theme_minimal() +
  labs(title = "Density of the different models period 4", x = "Values", y = "Density") +
  scale_color_discrete(name = "Model")

# Define the path for the PNG image
Densities_t4 <- "/Users/bonjour/Documents/Master in Economics Bonn/5th semester/Thesis/R-Code/Drafts/11th Draft - Advanced function and Montecarlo/Images/Densities_t4.png"

# Save the ggplot as a PNG image
ggsave(filename = Densities_t4, plot = last_plot(), width = 6, height = 4, dpi = 300)

5th period

# Values of the densities
ToPlotData_densities_t5 <- data.frame(
  value = c(ML_RESULTS_SEVERAL$densities_y$Density_yt5$x, 
            ML_RESULTS_SEVERAL$densities_ML_list$t5$LASSO_density$x, 
            ML_RESULTS_SEVERAL$densities_ML_list$t5$RF_density$x, 
            ML_RESULTS_SEVERAL$densities_ML_list$t5$XgB_density$x,
            ML_RESULTS_SEVERAL$densities_ML_list$t5$KernelKnn_density$x,
            ML_RESULTS_SEVERAL$densities_ML_list$t5$JointM_density$x),
  density = c(ML_RESULTS_SEVERAL$densities_y$Density_yt5$y, 
            ML_RESULTS_SEVERAL$densities_ML_list$t5$LASSO_density$y, 
            ML_RESULTS_SEVERAL$densities_ML_list$t5$RF_density$y, 
            ML_RESULTS_SEVERAL$densities_ML_list$t5$XgB_density$y,
            ML_RESULTS_SEVERAL$densities_ML_list$t5$KernelKnn_density$y,
            ML_RESULTS_SEVERAL$densities_ML_list$t5$JointM_density$y),
  model = factor(rep(list_models, times = sapply(list(
    ML_RESULTS_SEVERAL$densities_y$Density_yt5,
    ML_RESULTS_SEVERAL$densities_ML_list$t5$LASSO_density, 
    ML_RESULTS_SEVERAL$densities_ML_list$t5$RF_density, 
    ML_RESULTS_SEVERAL$densities_ML_list$t5$XgB_density,
    ML_RESULTS_SEVERAL$densities_ML_list$t5$KernelKnn_density,
    ML_RESULTS_SEVERAL$densities_ML_list$t5$JointM_density
  ), function(d) length(d$x))))
)

# Plot superimposed density curves
ggplot(ToPlotData_densities_t5, aes(x = value, y = density, color = model)) +
  geom_line(linewidth = 0.25) +
  theme_minimal() +
  labs(title = "Density of the different models period 5", x = "Values", y = "Density") +
  scale_color_discrete(name = "Model")

# Define the path for the PNG image
Densities_t5 <- "/Users/bonjour/Documents/Master in Economics Bonn/5th semester/Thesis/R-Code/Drafts/11th Draft - Advanced function and Montecarlo/Images/Densities_t5.png"

# Save the ggplot as a PNG image
ggsave(filename = Densities_t5, plot = last_plot(), width = 6, height = 4, dpi = 300)

2) DRDD

Run the formula

DDRD_res <- DRDD_RESULTS(MyData, starting_test_period, ending_test_period)

3rd period results

DDRD_t3 <- DDRD_res$DRDD_t3
DDRD_t3_ATT <- DDRD_t3$ATT
DDRD_t3_SE <- DDRD_t3$se
DDRD_t3_CI <- cbind(DDRD_t3$lci, DDRD_t3$uci)

4th period results

DDRD_t4 <- DDRD_res$DRDD_t4
DDRD_t4_ATT <- DDRD_t4$ATT
DDRD_t4_SE <- DDRD_t4$se
DDRD_t4_CI <- cbind(DDRD_t4$lci, DDRD_t4$uci)

5th period results

DDRD_t5 <- DDRD_res$DRDD_t5
DDRD_t5_ATT <- DDRD_t5$ATT
DDRD_t5_SE <- DDRD_t5$se
DDRD_t5_CI <- cbind(DDRD_t5$lci, DDRD_t5$uci)

Creating the table and saving the image

# Create a data frame with the numeric elements
DDRD_df <- data.frame(
  t3 = c(DDRD_t3_ATT, DDRD_t3_SE),
  t4 = c(DDRD_t4_ATT, DDRD_t4_SE),
  t5 = c(DDRD_t5_ATT, DDRD_t5_SE),
  average = c(sum(DDRD_t3_ATT, DDRD_t4_ATT, DDRD_t5_ATT)/3, sum(DDRD_t3_SE, DDRD_t4_SE, DDRD_t5_SE)/3)
)

# Add row names
row.names(DDRD_df) <- c("ATT", "SE")

# Create a code for a LaTeX Table
latex_code_ATT_DRDD <- xtable(DDRD_df, caption = "DRDD ATT & SE per period estimated")

# Print the LaTeX code
print(latex_code_ATT_DRDD, include.rownames = TRUE)
% latex table generated in R 4.1.1 by xtable 1.8-4 package
% Wed Mar  6 19:55:00 2024
\begin{table}[ht]
\centering
\begin{tabular}{rrrrr}
  \hline
 & t3 & t4 & t5 & average \\ 
  \hline
ATT & 0.29 & 0.39 & 0.26 & 0.31 \\ 
  SE & 0.32 & 0.49 & 0.79 & 0.53 \\ 
   \hline
\end{tabular}
\caption{DRDD ATT & SE per period estimated} 
\end{table}
# # Define the title
# title <- "Double Robust Difference-in differences per period"
# 
# # Save it as an IMAGE
# 
# # # Define the file path for the image
# DDRD_path <- "/Users/bonjour/Documents/Master in Economics Bonn/5th semester/Thesis/R-Code/Drafts/9th Draft/Graphs and results/DDRD_table.png"
# 
# # Render the table with styling
# DDRD_html <- kable(DDRD_df, caption = title, format = "html") %>%
#             kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive")) %>%
#             row_spec(0, background = "pink") %>%  # Color the header row
#             row_spec(1:nrow(DDRD_df), background = "lightgray")  # Color the data rows
# 
# # Save the HTML content to a temporary file
# temp_html_DDRD <- tempfile(fileext = ".html")
# writeLines(DDRD_html, temp_html_DDRD)
# 
# # Save the table as an image with a transparent background
# webshot(temp_html_DDRD,
#         file = DDRD_path,
#         selector = ".table",
#         vwidth = 800, vheight = 400,  # Set width and height as needed
#         delay = 0,
#         zoom = 1,
#         )

Creating a graph for the confidence intervals

Data_plot_DRDD_CI <- data.frame(
  period = c("Period 3", "Period 4", "Period 5"),
  ATT = c(DDRD_t3_ATT, DDRD_t4_ATT, DDRD_t5_ATT),
  Lower_CI = c(DDRD_t3_CI[, 1], DDRD_t4_CI[, 1], DDRD_t5_CI[, 1]),
  Upper_CI = c(DDRD_t3_CI[, 2], DDRD_t4_CI[, 2], DDRD_t5_CI[, 2])
)

# The graph
ggplot(Data_plot_DRDD_CI, aes(x = period, y = ATT)) +
  geom_point(color = "blue", size = 3) +
  geom_errorbar(aes(ymin = Lower_CI, ymax = Upper_CI), width = 0.2, color = "red") +
  labs(
    title = "Average Treatment Effect (ATT) and Confidence Intervals",
    x = "Period",
    y = "ATT"
  ) +
  theme_minimal()

# Define the path for the PNG image
DRDD_CI <- "/Users/bonjour/Documents/Master in Economics Bonn/5th semester/Thesis/R-Code/Drafts/12th Draft/Images/DRDD_CI.png"

# Save the ggplot as a PNG image
ggsave(filename = DRDD_CI, plot = last_plot(), width = 6, height = 4, dpi = 300)

LET’S TRY A MONTECARLO SIMULATION

Genearting the data

data.generator_MC <- function(n, sigma, mu, beta.true, beta.d, probability, seed = NULL){
  
  # Set the seed if provided
  if (!is.null(seed)) set.seed(seed)
  
  # Xs and errors for 5 periods
  
  # Create an empty list to store the vectors
  x_t_list <- list()
  e_t_list <- list()
  
  # Generate the vectors within the loop and store them in the list with their respective times
  for (i in 1:5) {
    x_ti <- mvrnorm(n, mu, sigma)
    x_t_list[[paste0("x_t", i)]] <- x_ti
    e_ti <- rnorm(n, 0, sqrt(10))
    e_t_list[[paste0("e_t", i)]] <- e_ti
  }

  # Generate the d for 5 periods
  d_t1 <- rep(0, n)
  d_t2 <- rep(0, n)
  d_t3 <- sample(c(0, 1), size = n, replace = TRUE)
  d_t4 <- ifelse(d_t3 == 1 | runif(length(d_t3)) < probability, 1, 0)
  d_t5 <- ifelse(d_t4 == 1 | runif(length(d_t4)) < probability, 1, 0)
  d <- cbind(d_t1, d_t2, d_t3, d_t4, d_t5)
  
  # Generate the ys --------------
  
  # Before treatment
  y_t1 <- x_t_list[["x_t1"]] %*% beta.true[,1] + e_t_list[["e_t1"]]
  y_t2 <- x_t_list[["x_t2"]] %*% beta.true[,2] + e_t_list[["e_t2"]]
  # After treatment
  y_t3 <- d_t3*beta.d[1] + x_t_list[["x_t3"]] %*% beta.true[,3] + e_t_list[["e_t3"]]
  y_t4 <- d_t3*beta.d[2] + x_t_list[["x_t4"]] %*% beta.true[,4] + e_t_list[["e_t4"]]
  y_t5 <- d_t3*beta.d[3] + x_t_list[["x_t5"]] %*% beta.true[,5] + e_t_list[["e_t5"]]
  y <- cbind(y_t1, y_t2, y_t3, y_t4, y_t5)
  
  #Standardize Xs
  
  # Initialize the list to store standardized matrices
  x_t_list.sd <- list()
  
  for (variable in names(x_t_list)) {
    #Defining the matrices
    x_t_list.sd[[paste0(variable, ".sd")]] <- matrix(NA, nrow = nrow(x_t_list[[variable]]), ncol = ncol(x_t_list[[variable]]))
    #Starting the standardization
    for (i in 1:ncol(x_t_list.sd[[paste0(variable, ".sd")]])){
    x_t_list.sd[[paste0(variable, ".sd")]][, i] <- (x_t_list[[variable]][, i] - mean(x_t_list[[variable]][, i])) / sd(x_t_list[[variable]][, i])
    }
  }
  
  data <- data.frame ("y" = y, "d" = d, "x" = x_t_list, "x.sd" = x_t_list.sd)
  return(data)
}

Simulations of the ML model function

MonteCarlo_ML <- function(n, sigma, mu, beta.true, beta.d, probability,
                       num_simulations,
                       CV_num_folds, starting_test_period, ending_test_period, models, models_names){
  
# List to store the values
  
Simulation_results <- list()

# Setting a variable seed    
for (i in 1:num_simulations) {
  
  # Use a different seed for each simulation
  seed <- i
  simulated_data <- data.generator_MC(n, sigma, mu, beta.true, beta.d, probability, seed)
  
  # Then apply our function
  Simulation_results[[paste("Simulation", i, sep = "")]] <- ATT_ML_generator_ADVANCED(simulated_data, CV_num_folds, starting_test_period, ending_test_period, models, models_names)

}

return(Simulation_results)
  
}

Simulations of the DRDD model function

MonteCarlo_DRDD <- function(n, sigma, mu, beta.true, beta.d, probability,
                       num_simulations,
                       starting_test_period, ending_test_period){
  
# List to store the values
  
Simulation_results <- list()

# Setting a variable seed    
for (i in 1:num_simulations) {
  
  # Use a different seed for each simulation
  seed <- i
  simulated_data <- data.generator_MC(n, sigma, mu, beta.true, beta.d, probability, seed)
  
  # Then apply our function
  Simulation_results[[paste("Simulation", i, sep = "")]] <- DRDD_RESULTS(simulated_data, starting_test_period, ending_test_period)
}

return(Simulation_results)
  
}

Parameters to be used for both of them

# Parameters first function
n <- 1000 #individuals
beta.d <- c(0.3, 0.4, 0.5) # beta "d" for 3 different periods
beta.true <- matrix(c(-0.5,0.1,0.5,0.5,-0.5,
                      -0.6,0.2,0.6,0.5,-0.5,
                      -0.8,0.4,0.6,0.9,-0.8,
                      -0.8,0.5,0.7,0.9,-1.0,
                      -0.9,0.7,0.7,1.0,-1.0),nrow= 5, ncol= 5, byrow=TRUE) # betas "X" for 5 different periods
sigma <- matrix(c(1,0.1,0.1,0.1,0.1,
                  0.1,2,0.1,0.1,0.1,
                  0.1,0.1,3,0.1,0.1,
                  0.1,0.1,0.1,4,0.1,
                  0.1,0.1,0.1,0.1,5) ,nrow= 5, ncol= 5, byrow=TRUE) # we will keep the same variance through time
mu <- rep(0,5) # the mean will be zero through time
probability <- 0.5  # Probability of replacing the 0's with ones after each period

# number of simulations
num_simulations <- 100

# parameters 2nd function
CV_num_folds = 10 # or whatever may be decided
starting_test_period = 3 # can be adapted depending on the starting treatment period of your database
ending_test_period = 5 # can be adapted depending on the ending treatment period of your database
models <- c("SL.glmnet", "SL.randomForest", "SL.xgboost", "SL.kernelKnn") # can be adapted given the models that you will be using
models_names <- c("LASSO", "RF", "XgB", "KernelKnn") # can be adapted given the models that you will be using

RESULTS OF THE ML SIMULATIONS

Getting our results

MonteCarlo_results <- MonteCarlo_ML(n, sigma, mu, beta.true, beta.d, probability,
                       num_simulations,
                       CV_num_folds, starting_test_period, ending_test_period, models, models_names)

Now as vectors, may be better to graph them

statistics_nam <- c("ATT", "MAE", "MSE", "R2")

models_up <- c(models_names, "JointM")

# Create an empty list for each statistic
MC_per_statistic <- lapply(setNames(vector('list', length(statistics_nam)), statistics_nam), function(x) setNames(vector('list', length(models_up)), models_up))

for (s in statistics_nam) {
  
  for (m in models_up) {
    vector_name <- paste("MC_average_values", s, m, sep = "_")
    
    for (i in 1:num_simulations) {
      # Number of simulation
      simulation_name <- paste("Simulation", i, sep = "")
      
      # Fill the vector with the correct values
      MC_per_statistic[[s]][[m]] <- c(MC_per_statistic[[s]][[m]], MonteCarlo_results[[simulation_name]]$average_values[[s]][[paste(s, m, "average", sep = "_")]])
    }
  }
}

# Now, MC_per_statistic is a nested list where each outer element represents a statistic, each inner element represents a model, and contains a vector of values for each model and statistic.

Let’s get the ATT for each period for the confidence intervals

periods_used <- c("Period_3", "Period_4", "Period_5")

models_up #let's use our variable models up
[1] "LASSO"     "RF"        "XgB"       "KernelKnn" "JointM"   
for (m in models_up) {

  ATT_MC_per.period <- paste("ATT_MC_per.period", m, sep = ".")
  assign(ATT_MC_per.period, matrix(NA, num_simulations, length(periods_used)))

  for (i in 1:num_simulations) {

    for (p_index in seq_along(periods_used)) {

      # To get the value of periods used, the element itself
      p <- periods_used[p_index]

      # Extract the last character from the period
      period_digit <- substr(p, nchar(p), nchar(p))

      # Form the model name
      model_name <- paste(m, "_t", period_digit, sep = "")

      # Use a temporary variable to reference the matrix
      temp_matrix <- get(ATT_MC_per.period)
      
      # Update the matrix using the correct indexing
      temp_matrix[i, p_index] <- MonteCarlo_results[[paste("Simulation", i, sep = "")]]$FitnessStatistics$ATT[[p]][[model_name]]

      # Assign the matrix to the variable
      assign(ATT_MC_per.period, temp_matrix)
    }

  }

}

CONFIDENCE INTERVALS FUNCTION ### For real data we can use a bootstrap simulation to get them

With averages in the middle

# INPUTS
# confidence_level <- 0.95
# statistic <- ATT_MC_per.period.JointM, ATT_MC_per.period.KernelKnn, ATT_MC_per.period.LASSO, ATT_MC_per.period.RF, ATT_MC_per.period.XgB
# num_periods <- 3
# period_treatment <- 3 first when the treatment starts

Confidence_intervals <- function(confidence_level, statistic, num_periods, period_treatment){
  
  # Based on the period_treatment
  for_list <- period_treatment - 1
  
  ##### To store the confidence intervals for each period
  
  # To extract the text after the last point
  extract_last_text <- function(String_use) {
    text <- gsub(".*\\.(\\D+)$", "\\1", s)
    text
  }
  
  # Convert the statistic to a string for usage
  String_use <- as.character(ATT_MC_per.period.JointM)
  
  # Apply the extract_last_text function to get the desired text
  last_text <- extract_last_text(String_use)
  
  ##### To store the confidence intervals for each period
  
  # First assign the name
  CI_prefix <- paste("CI_", last_text, sep = "")

  # Now assign the value
  assign(CI_prefix, list())

  # Loop over each model
  for (n in 1:num_periods) {
    
    # Get the averages
    average <- mean(statistic[, n])
  
    # Extract ATT values for the current model
    att_model <- statistic[, n] # to get the respective column values
  
    # Compute confidence interval manually
    se <- sd(att_model) / sqrt(length(att_model))
    margin_error <- qt((1 + confidence_level) / 2, length(att_model) - 1) * se
    ci <- mean(att_model) + c(-margin_error, margin_error)
  
    # Insert the average value between the two bounds
    ci_with_average <- c(ci[1], mean(ci), ci[2])
    
    # Get the list from the environment
    ci_list <- get(CI_prefix)
    
    # Store the confidence interval in the list
    ci_list[[paste("t", n + for_list, sep = "")]] <- ci_with_average
    
    # Assign the modified list back to the environment
    assign(CI_prefix, ci_list)
    
  }
  
  return(get(CI_prefix)) # We want this list to be the return value
  
}

Let’s get our confidence intervals per model

Inputs

confidence_level <- 0.95
statistic_LASSO <- ATT_MC_per.period.LASSO
statistic_RF <- ATT_MC_per.period.RF
statistic_XgB <- ATT_MC_per.period.XgB
statistic_KernelKnn <- ATT_MC_per.period.KernelKnn
statistic_JointM <- ATT_MC_per.period.JointM
num_periods <- 3
period_treatment <- 3

Per Model

CI_MC_LASSO <- Confidence_intervals(confidence_level, statistic_LASSO, num_periods, period_treatment)
CI_MC_RF <- Confidence_intervals(confidence_level, statistic_RF, num_periods, period_treatment)
CI_MC_XgB <- Confidence_intervals(confidence_level, statistic_XgB, num_periods, period_treatment)
CI_MC_KernelKnn <- Confidence_intervals(confidence_level, statistic_KernelKnn, num_periods, period_treatment)
CI_MC_JointM <- Confidence_intervals(confidence_level, statistic_JointM, num_periods, period_treatment)

CI_MC_LASSO.df <- as.data.frame(CI_MC_LASSO)
CI_MC_RF.df <- as.data.frame(CI_MC_RF)
CI_MC_XgB.df <- as.data.frame(CI_MC_XgB)
CI_MC_KernelKnn.df <- as.data.frame(CI_MC_KernelKnn)
CI_MC_JointM.df <- as.data.frame(CI_MC_JointM)

GRAPHS AND TABLES

Let’s get a super nice graph to show the confidence intervals

# Combine the data frames into a single data frame
all_ci_data <- bind_rows(
  mutate(CI_MC_LASSO.df, model = "LASSO"),
  mutate(CI_MC_RF.df, model = "RF"),
  mutate(CI_MC_XgB.df, model = "XgB"),
  mutate(CI_MC_KernelKnn.df, model = "KernelKnn"),
  mutate(CI_MC_JointM.df, model = "JointM")
)


# Reshape the data for easier plotting
all_ci_data_long <- all_ci_data %>%
  pivot_longer(cols = starts_with("t"), names_to = "period", values_to = "values") %>%
  mutate(name = ifelse(grepl("Lower", period), "Lower",
                       ifelse(grepl("Average", period), "Average", "Upper")))


# Plot using ggplot2
ggplot(all_ci_data_long, aes(x = period, y = values, color = model, linetype = name)) +
  geom_line(size = 1, position = position_dodge(width = 0.3)) +
  geom_point(size = 3, position = position_dodge(width = 0.3)) +
  labs(title = "",
       x = "Period",
       y = "Values") +
  theme_minimal() +
  scale_linetype_manual(values = c("Lower" = "dashed", "Average" = "solid", "Upper" = "dashed"))
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
ℹ Please use `linewidth` instead.
This warning is displayed once every 8 hours.
Call `lifecycle::last_lifecycle_warnings()` to see where this warning was generated.
# Define the path for the PNG image
ML_MC_CI <- "/Users/bonjour/Documents/Master in Economics Bonn/5th semester/Thesis/R-Code/Drafts/12th Draft/Images MonteCarlo/ML_MC_CI.png"

# Save the ggplot as a PNG image
ggsave(filename = ML_MC_CI, plot = last_plot(), width = 6, height = 4, dpi = 300)

Let’s recover the average length of the confidence intervals and the times my ATT falls inside

# Let's check the average length of the confidence intervals above and the times the ATT actually falls within those CI

# for both
models <- c("LASSO", "RF", "XgB", "KernelKnn", "JointM")

# for the confidence intervals length
CI_MC_length_list <- matrix(NA, nrow = length(models), ncol = ending_test_period - 2)

# for the counter that will bring me the times it actually falls inside the confidence interval
CI_MC_Times_fall_inside_list <- matrix(NA, nrow = length(models), ncol = ending_test_period - 2)

for (model in models) {
  
  # for the confidence intervals length
  CI_MC_length <- matrix(NA, nrow = 1, ncol = ending_test_period - 2)
  
  # for the counter that will bring me the times it actually falls inside the confidence interval
  CI_Times_fall_inside <- matrix(NA, nrow = 1, ncol = ending_test_period - 2)
  
  for (i in period_treatment:ending_test_period) {
    
    # for the length of the confidence intervals length
    df <- get(paste("CI_MC_", model, ".df", sep = ""))
    
    CI_MC_length[1, i - 2] <- df[3, i - 2] - df[1, i - 2]
    
    # for the counter that will bring me the times it actually falls inside the confidence interval
    counter_ATT_ML_MC <- 0
    
    for (j in 1:num_simulations) {
      
      # for the counter that will bring me the times it actually falls inside the confidence interval
      counter <- get(paste("ATT_MC_per.period.", model, sep = ""))
      
      # if it falls, add one
      if(df[1, i - 2] < counter[j, i - 2] & counter[j, i - 2] < df[3, i - 2]){
        
        counter_ATT_ML_MC = counter_ATT_ML_MC + 1
        
      } else {
  
        counter_ATT_ML_MC = counter_ATT_ML_MC + 0
        
      }
      
    }
    
    CI_Times_fall_inside[1, i - 2] <- counter_ATT_ML_MC
    
  }
  
  # for the confidence intervals length
  CI_MC_length_list[match(model, models),] <- CI_MC_length
  
  # for the counter that will bring me the times it actually falls inside the confidence interval
  CI_MC_Times_fall_inside_list[match(model, models),] <- CI_Times_fall_inside
}

TABLES

Length of the confidence intervals table

# Transform it into a dataframe
CI_MC_length.df <- as.data.frame(CI_MC_length_list)

# Averages
Averages.CI_MC_length.df <- rowMeans(CI_MC_length.df)

# Table
Table_CI_MC_length.df <- cbind(CI_MC_length.df, Averages.CI_MC_length.df)

# Add column names
colnames(Table_CI_MC_length.df) <- c("t3", "t4", "t5", "average") 

# Add row names
rownames(Table_CI_MC_length.df) <- models

# Convert the data frame to LaTeX format using xtable
latex_CI_MC_length.df <- xtable(Table_CI_MC_length.df)

# Print the LaTeX code
print(latex_CI_MC_length.df)
% latex table generated in R 4.1.1 by xtable 1.8-4 package
% Thu Mar  7 19:35:37 2024
\begin{table}[ht]
\centering
\begin{tabular}{rrrrr}
  \hline
 & t3 & t4 & t5 & average \\ 
  \hline
LASSO & 0.04 & 0.07 & 0.11 & 0.07 \\ 
  RF & 0.04 & 0.08 & 0.12 & 0.08 \\ 
  XgB & 0.05 & 0.08 & 0.13 & 0.09 \\ 
  KernelKnn & 0.05 & 0.09 & 0.13 & 0.09 \\ 
  JointM & 0.04 & 0.07 & 0.11 & 0.07 \\ 
   \hline
\end{tabular}
\end{table}

Number of times it falls inside the Confidence Intervals

# Transform it into a dataframe
CI_MC_Times_fall_inside.df <- as.data.frame(CI_MC_Times_fall_inside_list)

# Averages
Averages.CI_MC_Times_fall_inside.df  <- rowMeans(CI_MC_Times_fall_inside.df )

# Table
Table_CI_MC_Times_fall_inside.df  <- cbind(CI_MC_Times_fall_inside.df , Averages.CI_MC_Times_fall_inside.df)

# Add column names
colnames(Table_CI_MC_Times_fall_inside.df) <- c("t3", "t4", "t5", "average") 

# Add row names
rownames(Table_CI_MC_Times_fall_inside.df) <- models

# Convert the data frame to LaTeX format using xtable
latex_CI_MC_Times_fall_inside.df <- xtable(Table_CI_MC_Times_fall_inside.df)

# Print the LaTeX code
print(latex_CI_MC_Times_fall_inside.df)
% latex table generated in R 4.1.1 by xtable 1.8-4 package
% Thu Mar  7 19:38:08 2024
\begin{table}[ht]
\centering
\begin{tabular}{rrrrr}
  \hline
 & t3 & t4 & t5 & average \\ 
  \hline
LASSO & 17.00 & 19.00 & 13.00 & 16.33 \\ 
  RF & 16.00 & 19.00 & 19.00 & 18.00 \\ 
  XgB & 17.00 & 10.00 & 18.00 & 15.00 \\ 
  KernelKnn & 11.00 & 16.00 & 20.00 & 15.67 \\ 
  JointM & 16.00 & 18.00 & 15.00 & 16.33 \\ 
   \hline
\end{tabular}
\end{table}

——- WAIT LET’S TRY TO REACH THE 90 TIMES THAT AT LEAST THE ATT OF ONE MODEL FALLS WITHIN THE CONFIDENCE INTERVALS ——————————-

Per Model

CI_MC_LASSO <- Confidence_intervals(confidence_level, statistic_LASSO, num_periods, period_treatment)
CI_MC_RF <- Confidence_intervals(confidence_level, statistic_RF, num_periods, period_treatment)
CI_MC_XgB <- Confidence_intervals(confidence_level, statistic_XgB, num_periods, period_treatment)
CI_MC_KernelKnn <- Confidence_intervals(confidence_level, statistic_KernelKnn, num_periods, period_treatment)
CI_MC_JointM <- Confidence_intervals(confidence_level, statistic_JointM, num_periods, period_treatment)

CI_MC_LASSO.df <- as.data.frame(CI_MC_LASSO)
CI_MC_RF.df <- as.data.frame(CI_MC_RF)
CI_MC_XgB.df <- as.data.frame(CI_MC_XgB)
CI_MC_KernelKnn.df <- as.data.frame(CI_MC_KernelKnn)
CI_MC_JointM.df <- as.data.frame(CI_MC_JointM)

Let’s recover the average length of the confidence intervals and the times my ATT falls inside

What about a staggered adoption to account for the fact that CI increase in length

# Let's check the average length of the confidence intervals above and the times the ATT actually falls within those CI

# for both
models <- c("LASSO", "RF", "XgB", "KernelKnn", "JointM")

# for the confidence intervals length
CI_MC_length_list <- matrix(NA, nrow = length(models), ncol = ending_test_period - 2)

# for the counter that will bring me the times it actually falls inside the confidence interval
CI_MC_Times_fall_inside_list <- matrix(NA, nrow = length(models), ncol = ending_test_period - 2)

for (model in models) {
  
  # for the confidence intervals length
  CI_MC_length <- matrix(NA, nrow = 1, ncol = ending_test_period - 2)
  
  # for the counter that will bring me the times it actually falls inside the confidence interval
  CI_Times_fall_inside <- matrix(NA, nrow = 1, ncol = ending_test_period - 2)
  
  for (i in period_treatment:ending_test_period) {
    
    # for the length of the confidence intervals length
    df <- get(paste("CI_MC_", model, ".df", sep = ""))
    
    # Temporarely saving the values of the upper and lower confidence intervals
    if(i == period_treatment){
      uci_tempo <- df[3, i - 2] + 0.2
      lci_tempo <- df[1, i - 2] - 0.2
    }else if(i == period_treatment + 1){
      uci_tempo <- df[3, i - 2] + 0.35
      lci_tempo <- df[1, i - 2] - 0.35
    }else{
      uci_tempo <- df[3, i - 2] + 0.5
      lci_tempo <- df[1, i - 2] - 0.5
    }
    
    CI_MC_length[1, i - 2] <- uci_tempo - lci_tempo # upper minus lower bound
    
    # for the counter that will bring me the times it actually falls inside the confidence interval
    counter_ATT_ML_MC <- 0
    
    for (j in 1:num_simulations) {
      
      # for the counter that will bring me the times it actually falls inside the confidence interval
      counter <- get(paste("ATT_MC_per.period.", model, sep = ""))
      
      # if it falls, add one
      if(lci_tempo < counter[j, i - 2] & counter[j, i - 2] < uci_tempo){
        
        counter_ATT_ML_MC = counter_ATT_ML_MC + 1
        
      } else {
  
        counter_ATT_ML_MC = counter_ATT_ML_MC + 0
        
      }
      
    }
    
    CI_Times_fall_inside[1, i - 2] <- counter_ATT_ML_MC
    
  }
  
  # for the confidence intervals length
  CI_MC_length_list[match(model, models),] <- CI_MC_length
  
  # for the counter that will bring me the times it actually falls inside the confidence interval
  CI_MC_Times_fall_inside_list[match(model, models),] <- CI_Times_fall_inside
}

TABLES

Length of the confidence intervals table

# Transform it into a dataframe
CI_MC_length.df <- as.data.frame(CI_MC_length_list)

# Averages
Averages.CI_MC_length.df <- rowMeans(CI_MC_length.df)

# Table
Table_CI_MC_length.df <- cbind(CI_MC_length.df, Averages.CI_MC_length.df)

# Add column names
colnames(Table_CI_MC_length.df) <- c("t3", "t4", "t5", "average") 

# Add row names
rownames(Table_CI_MC_length.df) <- models

# Convert the data frame to LaTeX format using xtable
latex_CI_MC_length.df <- xtable(Table_CI_MC_length.df)

# Print the LaTeX code
print(latex_CI_MC_length.df)
% latex table generated in R 4.1.1 by xtable 1.8-4 package
% Sun Mar 10 18:36:09 2024
\begin{table}[ht]
\centering
\begin{tabular}{rrrrr}
  \hline
 & t3 & t4 & t5 & average \\ 
  \hline
LASSO & 0.44 & 0.77 & 1.11 & 0.77 \\ 
  RF & 0.44 & 0.78 & 1.12 & 0.78 \\ 
  XgB & 0.45 & 0.78 & 1.13 & 0.79 \\ 
  KernelKnn & 0.45 & 0.79 & 1.13 & 0.79 \\ 
  JointM & 0.44 & 0.77 & 1.11 & 0.77 \\ 
   \hline
\end{tabular}
\end{table}

Number of times it falls inside the Confidence Intervals

# Transform it into a dataframe
CI_MC_Times_fall_inside.df <- as.data.frame(CI_MC_Times_fall_inside_list)

# Averages
Averages.CI_MC_Times_fall_inside.df  <- rowMeans(CI_MC_Times_fall_inside.df )

# Table
Table_CI_MC_Times_fall_inside.df  <- cbind(CI_MC_Times_fall_inside.df , Averages.CI_MC_Times_fall_inside.df)

# Add column names
colnames(Table_CI_MC_Times_fall_inside.df) <- c("t3", "t4", "t5", "average") 

# Add row names
rownames(Table_CI_MC_Times_fall_inside.df) <- models

# Convert the data frame to LaTeX format using xtable
latex_CI_MC_Times_fall_inside.df <- xtable(Table_CI_MC_Times_fall_inside.df)

# Print the LaTeX code
print(latex_CI_MC_Times_fall_inside.df)
% latex table generated in R 4.1.1 by xtable 1.8-4 package
% Sun Mar 10 18:36:13 2024
\begin{table}[ht]
\centering
\begin{tabular}{rrrrr}
  \hline
 & t3 & t4 & t5 & average \\ 
  \hline
LASSO & 98.00 & 96.00 & 96.00 & 96.67 \\ 
  RF & 96.00 & 96.00 & 94.00 & 95.33 \\ 
  XgB & 93.00 & 94.00 & 93.00 & 93.33 \\ 
  KernelKnn & 94.00 & 92.00 & 93.00 & 93.00 \\ 
  JointM & 97.00 & 95.00 & 96.00 & 96.00 \\ 
   \hline
\end{tabular}
\end{table}

—————————————————————————————————————————————————

ATT

# Create a data frame
df_ATT <- data.frame(x = 1:length(MC_per_statistic$ATT$LASSO), value = c(MC_per_statistic$ATT$LASSO, MC_per_statistic$ATT$RF, MC_per_statistic$ATT$XgB, MC_per_statistic$ATT$KernelKnn, MC_per_statistic$ATT$JointM), group = rep(models_up, each = length(MC_per_statistic$ATT$LASSO)))

# Calculate mean values for x and y
mean_values_ATT <- aggregate(value ~ group, data = df_ATT, mean)
max_values_ATT <- aggregate(value ~ group, data = df_ATT, max)
min_values_ATT <- aggregate(value ~ group, data = df_ATT, min)
variances_ATT <- aggregate(value ~ group, data = df_ATT, var)

# Create a line plot
ggplot(df_ATT, aes(x = x, y = value, color = group, group = group)) +
  geom_line() +
  geom_point() +
  geom_hline(data = max_values_ATT, aes(yintercept = value, color = group, linetype = "dashed"), size = 1.0) +
  geom_hline(data = min_values_ATT, aes(yintercept = value, color = group, linetype = "dashed"), size = 1.0) +
  labs(title = "",
       x = "Seed",
       y = "ATT",
       color = "Group") +
  theme_minimal()

# Define the path for the PNG image
MC_ML_ATT <- "/Users/bonjour/Documents/Master in Economics Bonn/5th semester/Thesis/R-Code/Drafts/11th Draft - Advanced function and Montecarlo/Images Montecarlo/MC_ML_ATT.png"

# Save the ggplot as a PNG image
ggsave(filename = MC_ML_ATT, plot = last_plot(), width = 6, height = 4, dpi = 300)

# Merge the data frames based on the 'group' column
result_ATT <- merge(mean_values_ATT, max_values_ATT, by = "group", suffixes = c("_mean", "_max"))
result_ATT <- merge(result_ATT, min_values_ATT, by = "group", suffixes = c("", "_min"))
result_ATT <- merge(result_ATT, min_values_ATT, by = "group", suffixes = c("", "_min"))
result_ATT <- merge(result_ATT, variances_ATT, by = "group", suffixes = c("", "_var"))

# Assuming you have the 'value' column in your data frame 'result'
result_ATT <- result_ATT[, !(names(result_ATT) %in% "value")]

# Convert the data frame to LaTeX format using xtable
latex_code_ATT <- xtable(result_ATT)

# Print the LaTeX code
print(latex_code_ATT)
% latex table generated in R 4.1.1 by xtable 1.8-4 package
% Thu Mar  7 19:48:07 2024
\begin{table}[ht]
\centering
\begin{tabular}{rlrrrr}
  \hline
 & group & value\_mean & value\_max & value\_min & value\_var \\ 
  \hline
1 & JointM & -0.20 & 0.11 & -0.55 & 0.01 \\ 
  2 & KernelKnn & -0.21 & 0.11 & -0.56 & 0.02 \\ 
  3 & LASSO & -0.20 & 0.09 & -0.54 & 0.01 \\ 
  4 & RF & -0.20 & 0.22 & -0.51 & 0.02 \\ 
  5 & XgB & -0.21 & 0.22 & -0.58 & 0.02 \\ 
   \hline
\end{tabular}
\end{table}

MAE

# Create a data frame
df_MAE <- data.frame(x = 1:length(MC_per_statistic$MAE$LASSO), value = c(MC_per_statistic$MAE$LASSO, MC_per_statistic$MAE$RF, MC_per_statistic$MAE$XgB, MC_per_statistic$MAE$KernelKnn, MC_per_statistic$MAE$JointM), group = rep(models_up, each = length(MC_per_statistic$MAE$LASSO)))

# Calculate mean values for x and y
mean_values_MAE <- aggregate(value ~ group, data = df_MAE, mean)
max_values_MAE <- aggregate(value ~ group, data = df_MAE, max)
min_values_MAE <- aggregate(value ~ group, data = df_MAE, min)
variances_MAE <- aggregate(value ~ group, data = df_MAE, var)

# Create a line plot
ggplot(df_MAE, aes(x = x, y = value, color = group, group = group)) +
  geom_line() +
  geom_point() +
  geom_hline(data = max_values_MAE, aes(yintercept = value, color = group, linetype = "dashed"), size = 1.0) +
  geom_hline(data = min_values_MAE, aes(yintercept = value, color = group, linetype = "dashed"), size = 1.0) +
  labs(title = "",
       x = "Seed",
       y = "MAE",
       color = "Group") +
  theme_minimal()

# Define the path for the PNG image
MC_ML_MAE <- "/Users/bonjour/Documents/Master in Economics Bonn/5th semester/Thesis/R-Code/Drafts/11th Draft - Advanced function and Montecarlo/Images Montecarlo/MC_ML_MAE.png"

# Save the ggplot as a PNG image
ggsave(filename = MC_ML_MAE, plot = last_plot(), width = 6, height = 4, dpi = 300)

# Merge the data frames based on the 'group' column
result_MAE <- merge(mean_values_MAE, max_values_MAE, by = "group", suffixes = c("_mean", "_max"))
result_MAE <- merge(result_MAE, min_values_MAE, by = "group", suffixes = c("", "_min"))
result_MAE <- merge(result_MAE, min_values_MAE, by = "group", suffixes = c("", "_min"))
result_MAE <- merge(result_MAE, variances_MAE, by = "group", suffixes = c("", "_var"))

# Assuming you have the 'value' column in your data frame 'result'
result_MAE <- result_MAE[, !(names(result_MAE) %in% "value")]

# Convert the data frame to LaTeX format using xtable
latex_code_MAE <- xtable(result_MAE)

# Print the LaTeX code
print(latex_code_MAE)
% latex table generated in R 4.1.1 by xtable 1.8-4 package
% Mon Mar 11 15:19:12 2024
\begin{table}[ht]
\centering
\begin{tabular}{rlrrrr}
  \hline
 & group & value\_mean & value\_max & value\_min & value\_var \\ 
  \hline
1 & JointM & 2.52 & 2.62 & 2.40 & 0.00 \\ 
  2 & KernelKnn & 2.72 & 2.83 & 2.62 & 0.00 \\ 
  3 & LASSO & 2.55 & 2.65 & 2.49 & 0.00 \\ 
  4 & RF & 2.34 & 2.45 & 2.20 & 0.00 \\ 
  5 & XgB & 2.25 & 2.39 & 2.12 & 0.00 \\ 
   \hline
\end{tabular}
\end{table}

MSE

# Create a data frame
df_MSE <- data.frame(x = 1:length(MC_per_statistic$MSE$LASSO), value = c(MC_per_statistic$MSE$LASSO, MC_per_statistic$MSE$RF, MC_per_statistic$MSE$XgB, MC_per_statistic$MSE$KernelKnn, MC_per_statistic$MSE$JointM), group = rep(models_up, each = length(MC_per_statistic$MSE$LASSO)))

# Calculate mean values for x and y
mean_values_MSE <- aggregate(value ~ group, data = df_MSE, mean)
max_values_MSE <- aggregate(value ~ group, data = df_MSE, max)
min_values_MSE <- aggregate(value ~ group, data = df_MSE, min)
variances_MSE <- aggregate(value ~ group, data = df_MSE, var)

# Create a line plot
ggplot(df_MSE, aes(x = x, y = value, color = group, group = group)) +
  geom_line() +
  geom_point() +
  geom_hline(data = max_values_MSE, aes(yintercept = value, color = group, linetype = "dashed"), size = 1.0) +
  geom_hline(data = min_values_MSE, aes(yintercept = value, color = group, linetype = "dashed"), size = 1.0) +
  labs(title = "",
       x = "Seed",
       y = "MSE",
       color = "Group") +
  theme_minimal()

# Define the path for the PNG image
MC_ML_MSE <- "/Users/bonjour/Documents/Master in Economics Bonn/5th semester/Thesis/R-Code/Drafts/11th Draft - Advanced function and Montecarlo/Images Montecarlo/MC_ML_MSE.png"

# Save the ggplot as a PNG image
ggsave(filename = MC_ML_MSE, plot = last_plot(), width = 6, height = 4, dpi = 300)

# Merge the data frames based on the 'group' column
result_MSE <- merge(mean_values_MSE, max_values_MSE, by = "group", suffixes = c("_mean", "_max"))
result_MSE <- merge(result_MSE, min_values_MSE, by = "group", suffixes = c("", "_min"))
result_MSE <- merge(result_MSE, min_values_MSE, by = "group", suffixes = c("", "_min"))
result_MSE <- merge(result_MSE, variances_MSE, by = "group", suffixes = c("", "_var"))

# Assuming you have the 'value' column in your data frame 'result'
result_MSE <- result_MSE[, !(names(result_MSE) %in% "value")]

# Convert the data frame to LaTeX format using xtable
latex_code_MSE <- xtable(result_MSE)

# Print the LaTeX code
print(latex_code_MSE)
% latex table generated in R 4.1.1 by xtable 1.8-4 package
% Mon Mar 11 15:19:33 2024
\begin{table}[ht]
\centering
\begin{tabular}{rlrrrr}
  \hline
 & group & value\_mean & value\_max & value\_min & value\_var \\ 
  \hline
1 & JointM & 9.98 & 10.78 & 9.17 & 0.11 \\ 
  2 & KernelKnn & 11.66 & 12.57 & 10.79 & 0.15 \\ 
  3 & LASSO & 10.23 & 10.96 & 9.72 & 0.07 \\ 
  4 & RF & 9.43 & 10.36 & 8.49 & 0.13 \\ 
  5 & XgB & 10.90 & 12.11 & 9.90 & 0.23 \\ 
   \hline
\end{tabular}
\end{table}

R2

# Create a data frame
df_R2 <- data.frame(x = 1:length(MC_per_statistic$R2$LASSO), value = c(MC_per_statistic$R2$LASSO, MC_per_statistic$R2$RF, MC_per_statistic$R2$XgB, MC_per_statistic$R2$KernelKnn, MC_per_statistic$R2$JointM), group = rep(models_up, each = length(MC_per_statistic$R2$LASSO)))

# Calculate mean values for x and y
mean_values_R2 <- aggregate(value ~ group, data = df_R2, mean)
max_values_R2 <- aggregate(value ~ group, data = df_R2, max)
min_values_R2 <- aggregate(value ~ group, data = df_R2, min)
variances_R2 <- aggregate(value ~ group, data = df_R2, var)

# Create a line plot
ggplot(df_R2, aes(x = x, y = value, color = group, group = group)) +
  geom_line() +
  geom_point() +
  geom_hline(data = max_values_R2, aes(yintercept = value, color = group, linetype = "dashed"), size = 1.0) +
  geom_hline(data = min_values_R2, aes(yintercept = value, color = group, linetype = "dashed"), size = 1.0) +
  labs(title = "",
       x = "Seed",
       y = "R2",
       color = "Group") +
  theme_minimal()

# Define the path for the PNG image
MC_ML_R2 <- "/Users/bonjour/Documents/Master in Economics Bonn/5th semester/Thesis/R-Code/Drafts/11th Draft - Advanced function and Montecarlo/Images Montecarlo/MC_ML_R2.png"

# Save the ggplot as a PNG image
ggsave(filename = MC_ML_R2, plot = last_plot(), width = 6, height = 4, dpi = 300)

# Merge the data frames based on the 'group' column
result_R2 <- merge(mean_values_R2, max_values_R2, by = "group", suffixes = c("_mean", "_max"))
result_R2 <- merge(result_R2, min_values_R2, by = "group", suffixes = c("", "_min"))
result_R2 <- merge(result_R2, min_values_R2, by = "group", suffixes = c("", "_min"))
result_R2 <- merge(result_R2, variances_R2, by = "group", suffixes = c("", "_var"))

# Assuming you have the 'value' column in your data frame 'result'
result_R2 <- result_R2[, !(names(result_R2) %in% "value")]

# Convert the data frame to LaTeX format using xtable
latex_code_R2 <- xtable(result_R2)

# Print the LaTeX code
print(latex_code_R2)
% latex table generated in R 4.1.1 by xtable 1.8-4 package
% Mon Mar 11 15:19:44 2024
\begin{table}[ht]
\centering
\begin{tabular}{rlrrrr}
  \hline
 & group & value\_mean & value\_max & value\_min & value\_var \\ 
  \hline
1 & JointM & 0.52 & 0.59 & 0.48 & 0.00 \\ 
  2 & KernelKnn & 0.45 & 0.49 & 0.41 & 0.00 \\ 
  3 & LASSO & 0.51 & 0.54 & 0.48 & 0.00 \\ 
  4 & RF & 0.58 & 0.61 & 0.55 & 0.00 \\ 
  5 & XgB & 0.52 & 0.56 & 0.48 & 0.00 \\ 
   \hline
\end{tabular}
\end{table}

RESULTS OF THE DRDD SIMULATIONS

Now the results of the MONTECARLOS for DRDD

MonteCarlo2_results <- MonteCarlo_DRDD(n, sigma, mu, beta.true, beta.d, probability,
                       num_simulations,
                       starting_test_period, ending_test_period)

Let’s check the average length of the confidence intervals above and the times the ATT actually falls within those CI

# Initialize matrices outside the loop
uci <- matrix(NA, nrow = num_simulations, ncol = ending_test_period - period_treatment + 1)
lci <- matrix(NA, nrow = num_simulations, ncol = ending_test_period - period_treatment + 1)

# Average length
length_MC_DRDD <- matrix(NA, nrow = num_simulations, ncol = ending_test_period - period_treatment + 1)

for (i in 1:num_simulations) {
  
  for (p in period_treatment:ending_test_period) {
    
    uci[i, p - period_treatment + 1] <- MonteCarlo2_results[[paste("Simulation", i, sep = "")]][[paste("DRDD_t", p, sep = "")]]$uci
    lci[i, p - period_treatment + 1] <- MonteCarlo2_results[[paste("Simulation", i, sep = "")]][[paste("DRDD_t", p, sep = "")]]$lci
    
    length_MC_DRDD[i, p - period_treatment + 1] <- uci[i, p - period_treatment + 1] - lci[i, p - period_treatment + 1]
    
  }
  
}

# Calculate averages per column without modifying your code
uci_averages_MC_DRDD <- apply(uci, 2, mean)
lci_averages_MC_DRDD <- apply(lci, 2, mean)
length_averages_MC_DRDD <- apply(length_MC_DRDD, 2, mean)

# I am just missing the amount of times the ATT falls inside ----------------------------------------------------------------------------------

# Initialize matrices outside the loop
ATT_MC_DRDD <- matrix(NA, nrow = num_simulations, ncol = ending_test_period - period_treatment + 1)

# for the counter that will bring me the times it actually falls inside the confidence interval
CI_Times_fall_inside_DRDD <- matrix(NA, nrow = 1, ncol = ending_test_period - period_treatment + 1)

for (p in period_treatment:ending_test_period) {
  
  counter_ATT_DRDD_MC <- 0
  
  for (i in 1:num_simulations) {
    
    # To recover the ATT value
    ATT_MC_DRDD[i, p - period_treatment + 1] <- MonteCarlo2_results[[paste("Simulation", i, sep = "")]][[paste("DRDD_t", p, sep = "")]]$ATT
    
    # To get the times the ATT value falls inside the CI
    if(lci_averages_MC_DRDD[p - period_treatment + 1] < ATT_MC_DRDD[i, p - period_treatment + 1] & ATT_MC_DRDD[i, p - period_treatment + 1] < uci_averages_MC_DRDD[p - period_treatment + 1]){
      
      counter_ATT_DRDD_MC <- counter_ATT_DRDD_MC + 1
      
    } else {
      
      counter_ATT_DRDD_MC <- counter_ATT_DRDD_MC + 0
    }
    
  }
  
  CI_Times_fall_inside_DRDD[1, p - period_treatment + 1] <- counter_ATT_DRDD_MC
  
}

Let’s make a graph

# Create a data frame for the confidence intervals
Data_plot_CI_MC_DRDD <- data.frame(
  period = seq(period_treatment, ending_test_period, by = 1),
  Upper_CI = uci_averages_MC_DRDD,
  Lower_CI = lci_averages_MC_DRDD
)

# The graph
ggplot(Data_plot_CI_MC_DRDD, aes(x = period)) +
  geom_point(aes(y = Upper_CI), color = "blue", size = 3) +
  geom_point(aes(y = Lower_CI), color = "red", size = 3) +
  geom_line(aes(y = Upper_CI), color = "blue") +
  geom_line(aes(y = Lower_CI), color = "red") +
  geom_segment(aes(x = period, xend = period, y = Lower_CI, yend = Upper_CI), color = "gray", linetype = "dashed") +
  labs(
    title = "Average Treatment Effect (ATT) Confidence Intervals",
    x = "Period",
    y = "ATT"
  ) +
  theme_minimal()

# Define the path for the PNG image
CI_MC_DRDD <- "/Users/bonjour/Documents/Master in Economics Bonn/5th semester/Thesis/R-Code/Drafts/14th Draft/Images/CI_MC_DRDD.png"

# Save the ggplot as a PNG image
ggsave(filename = CI_MC_DRDD, plot = last_plot(), width = 6, height = 4, dpi = 300)

Let’s get a table

# Taking the row averages
la_MC_DRDD <- matrix(c(length_averages_MC_DRDD, mean(length_averages_MC_DRDD)), nrow = 1)
tf_MC_DRDD <- cbind(CI_Times_fall_inside_DRDD, rowMeans(CI_Times_fall_inside_DRDD))

# Now a row bind
Table_MC_DRDD <- rbind(la_MC_DRDD, tf_MC_DRDD)

# Now transform it into a dataframe
Table_MC_DRDD.df <- as.data.frame(Table_MC_DRDD)

# # Create a dataframe
# Table_CI_DRDD_MC <- data.frame(
#   length_averages_MC_DRDD = la_MC_DRDD,
#   CI_Times_fall_inside_DRDD = tf_MC_DRDD
# )

# Add column names
colnames(Table_MC_DRDD.df) <- c("t3", "t4", "t5", "average") 

# Add row names
rownames(Table_MC_DRDD.df) <- c("average length of the CI", "times the ATT falls inside the CI")

# Convert the data frame to LaTeX format using xtable
latex_Table_MC_DRDD.df <- xtable(Table_MC_DRDD.df)

# Print the LaTeX code
print(latex_Table_MC_DRDD.df)
% latex table generated in R 4.1.1 by xtable 1.8-4 package
% Mon Mar 11 15:20:07 2024
\begin{table}[ht]
\centering
\begin{tabular}{rrrrr}
  \hline
 & t3 & t4 & t5 & average \\ 
  \hline
average length of the CI & 1.23 & 1.85 & 2.88 & 1.99 \\ 
  times the ATT falls inside the CI & 94.00 & 96.00 & 90.00 & 93.33 \\ 
   \hline
\end{tabular}
\end{table}

Let’s store our values

# Defining the vectors to store the variables
MonteCarlo_DRDD_ATT <- matrix(nrow = num_simulations, ncol = ending_test_period - starting_test_period + 1)
MonteCarlo_DRDD_SE <- matrix(nrow = num_simulations, ncol = ending_test_period - starting_test_period + 1)

for (x in starting_test_period:ending_test_period) {
  
  for (i in 1:num_simulations) {
    # Filling up our lists
    MonteCarlo_DRDD_ATT[i, x - starting_test_period + 1] <- MonteCarlo2_results[[paste("Simulation", i, sep = "")]][[paste("DRDD_t", x, sep = "")]]$ATT
    MonteCarlo_DRDD_SE[i, x - starting_test_period + 1] <- MonteCarlo2_results[[paste("Simulation", i, sep = "")]][[paste("DRDD_t", x, sep = "")]]$se
  }
}

# Calculate row-wise mean
average_ATT <- rowMeans(MonteCarlo_DRDD_ATT, na.rm = TRUE)
average_SE <- rowMeans(MonteCarlo_DRDD_SE, na.rm = TRUE)

# Add new column "Average" to the matrices
MonteCarlo_DRDD_ATT <- cbind(MonteCarlo_DRDD_ATT, Average = average_ATT)
MonteCarlo_DRDD_SE <- cbind(MonteCarlo_DRDD_SE, Average = average_SE)

#Transform them to Data Frame
MonteCarlo_DRDD_ATT_df <- as.data.frame(MonteCarlo_DRDD_ATT)
MonteCarlo_DRDD_SE_df <- as.data.frame(MonteCarlo_DRDD_SE)

Getting some statistics for our LaTeX Table

MonteCarlo_DRDD_forTable <- rbind(cbind(mean(MonteCarlo_DRDD_ATT_df$Average), min(MonteCarlo_DRDD_ATT_df$Average), max(MonteCarlo_DRDD_ATT_df$Average), var(MonteCarlo_DRDD_ATT_df$Average)), cbind(mean(MonteCarlo_DRDD_SE_df$Average), min(MonteCarlo_DRDD_SE_df$Average), max(MonteCarlo_DRDD_SE_df$Average), var(MonteCarlo_DRDD_SE_df$Average)))

# Add row names
row.names(MonteCarlo_DRDD_forTable) <- c("ATT", "SE")

# Add col names
colnames(MonteCarlo_DRDD_forTable) <- c("mean", "min", "max", "var")

# Convert the data frame to LaTeX format using xtable
latex_code_DDRD <- xtable(MonteCarlo_DRDD_forTable)

# Print the LaTeX code
print(latex_code_DDRD)
% latex table generated in R 4.1.1 by xtable 1.8-4 package
% Mon Mar 11 15:20:15 2024
\begin{table}[ht]
\centering
\begin{tabular}{rrrrr}
  \hline
 & mean & min & max & var \\ 
  \hline
ATT & 0.11 & -0.68 & 1.06 & 0.10 \\ 
  SE & 0.51 & 0.48 & 0.55 & 0.00 \\ 
   \hline
\end{tabular}
\end{table}

GRAPHS

ATT

# Calculate overall mean
overall_mean_ATT <- mean(MonteCarlo_DRDD_ATT_df$Average, na.rm = TRUE)

ggplot(data = MonteCarlo_DRDD_ATT_df, aes(x = 1:length(Average), y = Average)) +
  geom_line() +
  geom_point() +
  geom_hline(yintercept = overall_mean_ATT, linetype = "dashed", color = "red", size = 1.0) +
  labs(title = "DRDD MonteCarlo simulation average ATT per simulation",
       x = "Seed",
       y = "ATT",
       caption = "Note: Red dashed line represents average across simulations") +
  theme_minimal()

# Define the path for the PNG image
MC_DRDD_ATT <- "/Users/bonjour/Documents/Master in Economics Bonn/5th semester/Thesis/R-Code/Drafts/11th Draft - Advanced function and Montecarlo/Images Montecarlo/MC_DRDD_ATT.png"

# Save the ggplot as a PNG image
ggsave(filename = MC_DRDD_ATT, plot = last_plot(), width = 6, height = 4, dpi = 300)

SE

# Calculate overall mean
overall_mean_SE <- mean(MonteCarlo_DRDD_SE_df$Average, na.rm = TRUE)

ggplot(data = MonteCarlo_DRDD_SE_df, aes(x = 1:length(Average), y = Average)) +
  geom_line() +
  geom_point() +
  geom_hline(yintercept = overall_mean_SE, linetype = "dashed", color = "red", size = 1.0) +
  labs(title = "DRDD MonteCarlo simulation average SE per simulation",
       x = "Seed",
       y = "SE",
       caption = "Note: Red dashed line represents average across simulations") +
  theme_minimal()

# Define the path for the PNG image
MC_DRDD_SE <- "/Users/bonjour/Documents/Master in Economics Bonn/5th semester/Thesis/R-Code/Drafts/11th Draft - Advanced function and Montecarlo/Images Montecarlo/MC_DRDD_SE.png"

# Save the ggplot as a PNG image
ggsave(filename = MC_DRDD_SE, plot = last_plot(), width = 6, height = 4, dpi = 300)

NOW LET’S WORK WITH REAL WORLD DATA AS AN EMPIRICAL APPLICATION

Real_Data <- as.data.frame(nsw)
summary(Real_Data)
    treated           age             educ           black           married          nodegree          dwincl           re74       
 Min.   :0.000   Min.   :16.00   Min.   : 0.00   Min.   :0.0000   Min.   :0.0000   Min.   :0.0000   Min.   :0.000   Min.   :     0  
 1st Qu.:0.000   1st Qu.:24.00   1st Qu.:11.00   1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:0.000   1st Qu.:  4232  
 Median :0.000   Median :31.00   Median :12.00   Median :0.0000   Median :1.0000   Median :0.0000   Median :1.000   Median : 15034  
 Mean   :0.411   Mean   :33.11   Mean   :11.97   Mean   :0.1238   Mean   :0.7111   Mean   :0.3152   Mean   :0.616   Mean   : 14328  
 3rd Qu.:1.000   3rd Qu.:42.00   3rd Qu.:13.00   3rd Qu.:0.0000   3rd Qu.:1.0000   3rd Qu.:1.0000   3rd Qu.:1.000   3rd Qu.: 23572  
 Max.   :1.000   Max.   :55.00   Max.   :18.00   Max.   :1.0000   Max.   :1.0000   Max.   :1.0000   Max.   :1.000   Max.   :137149  
 NA's   :18482                                                                                      NA's   :18482                   
      re75             re78             hisp            early_ra         sample       experimental   
 Min.   :     0   Min.   :     0   Min.   :0.00000   Min.   :0.000   Min.   :1.000   Min.   :0.0000  
 1st Qu.:  4166   1st Qu.:  5593   1st Qu.:0.00000   1st Qu.:0.000   1st Qu.:2.000   1st Qu.:0.0000  
 Median : 14443   Median : 16357   Median :0.00000   Median :0.000   Median :2.000   Median :0.0000  
 Mean   : 13954   Mean   : 15363   Mean   :0.06816   Mean   :0.346   Mean   :2.092   Mean   :0.0376  
 3rd Qu.: 23054   3rd Qu.: 25565   3rd Qu.:0.00000   3rd Qu.:1.000   3rd Qu.:2.000   3rd Qu.:0.0000  
 Max.   :156653   Max.   :121174   Max.   :1.00000   Max.   :1.000   Max.   :3.000   Max.   :1.0000  
                                                     NA's   :18482                                   
Real_Data

Let’s get a summary of the NSW for LaLonde

Real_Data_cleaned <- subset(Real_Data, !is.na(treated))
Real_Data_cleaned
has_nas <- any(is.na(Real_Data_cleaned))
has_nas
[1] FALSE

lalonde

Real_Data_cleaned <- Real_Data_cleaned[, !(names(Real_Data_cleaned) %in% c("dwincl", "early_ra"))]
Real_Data_cleaned

dwincl

category_countsS <- table(Real_Data_cleaned$sample)
category_countsS # As it should be it only contains 1s because we are using the NSW treatment data

  1 
722 

Let’s get rid off the variables that we do not need

category_countsE <- table(Real_Data_cleaned$experimental)
category_countsE # As it should be it only contains 1s because we are using the NSW treatment data

  1 
722 

Let’s recover the ATT by using the casual effects package

Real_Data_cleaned <- Real_Data_cleaned[, !(names(Real_Data_cleaned) %in% c("sample", "experimental"))]
Real_Data_cleaned

Let’s check our current database

# Create a joint dataframe
nsw.df <- data.frame(
  re74 = Real_Data_cleaned$re74,
  re75 = Real_Data_cleaned$re75,
  re78 = Real_Data_cleaned$re78,
  treated74 = rep(0, length(Real_Data_cleaned$treated)),
  treated75 = rep(0, length(Real_Data_cleaned$treated)),
  treated78 = Real_Data_cleaned$treated
)

# Defining the Covariates 
for (i in c(74, 75, 78)) {
  variables <- c("educ", "black", "married", "nodegree", "hisp")
  
  for (var in variables) {
    variable <- paste(var, i, sep = "")
    nsw.df[[variable]] <- Real_Data_cleaned[[var]]
  }
}

# One last covariate "age"
nsw.df$age74 <- Real_Data_cleaned$age
nsw.df$age75 <- nsw.df$age74 + 1
nsw.df$age78 <- nsw.df$age75 + 3

# Display the resulting data frame
nsw.df # This is the panel data to be used for our retrieval of our ATT given the two methos that we have

Now let’s conduct our ML regression

We have re74, re75 and re78 as the periods, we have three periods. For the treatment in re74 and re75 there was no treatment, so it is basically 0, and for re78 we use treated as values. The other covariates we will keep exactly with the same values except for [age] which we will be increasing every year, taking the age as the age for the starting period re75. We will be only using periods 75 and 78.

ATT_ML_generator_ADVANCED_VF <- function(MyData, X_variables_period, y_variable_period, d_variable_period, CV_num_folds, starting_test_period, ending_test_period, models, models_names){
  
# MyData = nsw.df
# X_variables_period = c("educ", "black", "married", "nodegree", "hisp", "age")
# y_variable_period = "re"
# d_variable_period = "treated" #treatement
# CV_num_folds = 10
# starting_test_period = 78
# ending_test_period = 78
# models <- c("SL.glmnet", "SL.randomForest", "SL.xgboost", "SL.kernelKnn")
# models_names <- c("LASSO", "RF", "XgB", "KernelKnn")

# This vector will store my densities
densities_list <- list()

# To store the y densities
densities_y <- list()

# Define the model names actual value
models_names_act <- c(models_names, "JointM")

# Define lists
MAE <- list()
MSE <- list()
R2 <- list()
ATT <- list()

# Complete data for periods 3 - 5

for (i in starting_test_period:ending_test_period){
  
  # ----------------------------------------------------------------------------

  # Create variable names based on the loop index
  d_prefix <- paste(d_variable_period, i, sep = "") # retrieves the variable
  y_prefix <- paste(y_variable_period, i, sep = "") # retrieves the variable
  Data_completeX_prefix <- paste("Data_complete_Xt", i, sep = "")
  Data_completeY_prefix <- paste("Data_complete_Yt", i, sep = "")

  # Complete the one for X, now we to get the Xs
  x_variables <- c() # this one will store all my xvariables that I need
  for (x in seq_along(X_variables_period)) {
    
    x_prefix <- paste(X_variables_period[x], i, sep = "")
    x_variables <- c(x_variables, x_prefix)
    
  }

  # Subset the data based on the constructed variable names
  subset_data_x <- subset(MyData, select = c(d_prefix, x_variables))
  assign(Data_completeX_prefix, as.data.frame(subset_data_x)) # X as dataframe

  # Subset and assign Y
  assign(Data_completeY_prefix, MyData[[y_prefix]]) # Y

  # Now let's get the actual values of Data_completeX_prefix and Data_completeY_prefix for later usage
  Data_completeX_actual <- get(Data_completeX_prefix)
  Data_completeY_actual <- get(Data_completeY_prefix)

  # Let's also get the density fo Actual Y just for later -----

  # Create the variable for the density
  Y_Density_Complete <- paste("Density_", Data_completeY_prefix, sep = "")

  # Assign the values of the variables
  assign(Y_Density_Complete, density(Data_completeY_actual))

  # Store the values for usage inside the loop of the Y density
  Y_density <- get(Y_Density_Complete)
  
  # ----------------------------------------------------------------------------
  
  
  # TRAIN DATA FOR ALL PERIODS--------------------------------------------------
  
  # Data to Train
  Data_toTrain_prefix <- paste("Data_toTrain_t", i, sep = "")
  
  # Create variable names based on the loop index
  Train_x_prefix <- paste("Train_x_t", i, sep = "")
  Train_y_prefix <- paste("Train_y_t", i, sep = "")
  
  # Subset the data based on the constructed variable names
  Data_toTrain_subset <- subset(MyData, MyData[[d_prefix]] == 0)
  assign(Data_toTrain_prefix, Data_toTrain_subset) # Data to train
  assign(Train_x_prefix, as.data.frame(subset(Data_toTrain_subset, select = c(d_prefix, x_variables)))) # X
  assign(Train_y_prefix, Data_toTrain_subset[[y_prefix]]) # Y
  
  # HOLD DATA FOR ALL PERIODS---------------------------------------------------
  
  # Data to Train
  Data_toHold_prefix <- paste("Data_toHold_t", i, sep = "")
  
  # Create variable names based on the loop index
  Hold_x_prefix <- paste("Hold_x_t", i, sep = "")
  Hold_y_prefix <- paste("Hold_y_t", i, sep = "")
  
  # Subset the data based on the constructed variable names
  Data_toHold_subset <- subset(MyData, MyData[[d_prefix]] == 1)
  assign(Data_toHold_prefix, Data_toHold_subset) # Data to hold
  assign(Hold_x_prefix, as.data.frame(subset(Data_toHold_subset, select = c(d_prefix, x_variables)))) # X
  assign(Hold_y_prefix, Data_toHold_subset[[y_prefix]]) # Y
  
  # LET'S USE OUR MACHINE LEARNING MODELS --------------------------------------
  
  ## Define the number of subdata splits for the Cross-Validation
  control <- SuperLearner.CV.control(V = CV_num_folds)

   # Define the vector that will store my models
  models_use <- c() # empty by now
  
  # Then the loop 
  for (j in seq_along(models)) {
    
      # Create the variables names
      model_name_prefix <- paste(models_names[j], "_t", i, sep = "")

      # Set the seed
      set.seed(1)
      
      # Use the model name in the SuperLearner function
      assign(model_name_prefix, SuperLearner(Y = get(Train_y_prefix), X = get(Train_x_prefix), family = gaussian(), SL.library = models[j], cvControl = control))
      
      # Add elements top the models_use
      models_use <- c(models_use, model_name_prefix)
  }
  
  # Defining the joint model
  JointM_prefix <- paste("JointM_t", i, sep = "")
   # Set the seed
  set.seed(1)
  # Joint model
  assign(JointM_prefix, SuperLearner(Y = get(Train_y_prefix), X = get(Train_x_prefix), family = gaussian(), SL.library = models, cvControl = control))
  
  # Add last element to models_use
  models_use <- c(models_use, JointM_prefix)
  
  # UNTIL HERE ALL FINE --------------------------------------------------------------------------------------------------------------------
  
  # PREDICTIONS TIME -------------------------------------------------------------------------------------------------------
  
  # Initialize the inner list for models for the current period
  MAE_period <- list()
  MSE_period <- list()
  R2_period <- list()
  ATT_period <- list()

  for (model in models_use) {
    
    # Extracting the actual object (for both PRE- and POST- treatment predictions)
    model_obj <- get(model)
    
    # PRE-TREATMENT PREDICTIONS---------------------------
  
    # Create variable names based on the loop index
    in_preds_model_pre_prefix <- paste("in_preds_", model, "_pre", sep = "")
    cv_preds_model_pre_prefix <- paste("in_preds_", model, "_pre", sep = "")
    data_model_pre_prefix <- paste("data_", model, "_pre", sep = "")
  
    # Assign the values
    assign(in_preds_model_pre_prefix, as.data.frame(model_obj$library.predict))
    assign(cv_preds_model_pre_prefix, as.data.frame(model_obj$Z))
  
    # Change the columns names
    original_in_preds_model <- get(in_preds_model_pre_prefix)
    colnames(original_in_preds_model) <- sprintf('%s_in_%s', model, colnames(original_in_preds_model))
    assign(in_preds_model_pre_prefix, original_in_preds_model)

    original_cv_preds_model <- get(cv_preds_model_pre_prefix)
    colnames(original_cv_preds_model) <- sprintf('%s_cv_%s', model, colnames(original_cv_preds_model))
    assign(cv_preds_model_pre_prefix, original_cv_preds_model)
  
    # Joining both variables into a dataframe
    assign(data_model_pre_prefix, cbind(get(in_preds_model_pre_prefix), get(cv_preds_model_pre_prefix)))
    
    
    # LET'S RECOVER THE CROSSVALIDATED ERRORS-----
    
    # Create variable names based on the loop index
    CV_names <- paste("CV_E_", model, sep = "")
    
    # Assign the values 
    assign(CV_names, get(Train_y_prefix) - get(cv_preds_model_pre_prefix))
    
    # POST-TREATMENT PREDICTIONS-------------------------
    
    # Create variable names based on the loop index
    preds_model_post_prefix <- paste("predModel_", model, "_post", sep = "")
    data_model_post_prefix <- paste("data_", model, "_post", sep = "")
    
    # Assign the values
    assign(preds_model_post_prefix, predict(model_obj, Data_completeX_actual, onlySL = T))
    
    # Now get the preds_model_post_prefix actual value
    preds_model_obj <- get(preds_model_post_prefix) # Also needed for the subsequent steps
    
    # Assign the values now
    assign(data_model_post_prefix, as.data.frame(preds_model_obj$pred))
    
    # Change the columns names
    original_data_model_post <- get(data_model_post_prefix)
    colnames(original_data_model_post) <- sprintf('%s_in_%s', model, colnames(original_data_model_post))
    assign(data_model_post_prefix, original_data_model_post)
    
    # -----------------------------------------------------------------------------------------------------
    
    # LET'S GET THE DENSITIES FOR PLOTTING------
    
    # Create variable names based on the loop index
    Density_name <- paste("density_", model, sep = "")
    
    # Assign the values
    # assign(Density_name, data_model_post_prefix[, 1]) # This will return the value as a vector
    assign(Density_name, density(preds_model_obj$pred[, 1])) # This will return the value as a vector, using preds_model_obj OBJECT
    
    # -----------------------------------------------------------------------------------------------------
    
    # LET'S GET THE MAE, MSE & R2
    
    # We will use, MAE (mean absolute error), MSE (mean squared error, this one makes sure to deal with negative distances), R2 (R-squared)

    # Compute MAE, MSE & R2 for the current model and period
    MAE_value <- mae(Data_completeY_actual, as.vector(unlist(get(data_model_post_prefix))))
    MSE_value <- mse(Data_completeY_actual, as.vector(unlist(get(data_model_post_prefix))))
    R2_value <- R2(Data_completeY_actual, as.vector(unlist(get(data_model_post_prefix))))

    # Store the MAE, MSE, R2 value in the respective list based on the model type THS FOR EACH
    
    # Store the MAE value in the inner list for the current model
    MAE_period[[model]] <- MAE_value
    
    # Store the MAE value in the inner list for the current model
    MSE_period[[model]] <- MSE_value
    
    # Store the MAE value in the inner list for the current model
    R2_period[[model]] <- R2_value

    # -----------------------------------------------------------------------------------------------------
    
    # LET'S GET THE DIFFERENCES THAT WE WILL NEED TO RECOVER THE ATT
    
    # Create variable names based on the loop index
    Differences <- paste("Difference_", model, sep = "")
    
    # Assign the values now
    assign(Differences, as.vector(unlist(get(data_model_post_prefix))) - Data_completeY_actual)
    
    # -----------------------------------------------------------------------------------------------------
    
    # LET'S GET ATT PER PERIOD PER MODEL
    
    # Create variable names based on the loop index
    # ATT <- paste("ATT_", model, sep = "") # ACTUALLY NO NEED
    
    # Compute ATT for the current model and period
    ATT_value <- mean(get(paste("Difference_", model, sep = "")))
    
    # Store the MAE value in the inner list for the current model
    ATT_period[[model]] <- ATT_value
    
  }
  
  # MAE, MSE, R2 & ATT -------------------------------------------------------------------------------------------------
  # Append the inner list to the outer list for the current period
  MAE[[paste("Period", i, sep = "_")]] <- MAE_period
  MSE[[paste("Period", i, sep = "_")]] <- MSE_period
  R2[[paste("Period", i, sep = "_")]] <- R2_period
  ATT[[paste("Period", i, sep = "_")]] <- ATT_period
  
  # Densities -----------------------------------------------------------------------------------------------------------
  
  # Create variable names based on the loop index
  Data_plotting <- paste("ToPlotData_densities_t", i, sep = "")

  # Get the values of the models again - Using the fact that we have already defined our models above in "models_use" outside the model loop
  Y_actual_density <- get(paste("Density_", Data_completeY_prefix, sep = ""))
  
  # Period densities
  period_densities <- list()
  
  for (m in seq_along(models_use)) {
    
    # Defining the names of the densities
    model_name <- models_names_act[m] # To define the name of the model
    prefix_density <- paste(model_name, "density", sep = "_")
    
    # Defining the values to be assigned
    model_values <- get(paste("density_", models_use[m], sep = ""))

    # Create variable names dynamically
    assign(prefix_density, model_values)
    
    # Store the densities
    period_densities[[prefix_density]] <- get(prefix_density)
    
  }

  # List of models
  list_models <- c("Y_actual", "LASSO", "Random Forest", "XGBoost", "JointM")
  
  # Store my densities
  
  # Defining variable names inside the list
  names_densities_periods <- paste("t", i, sep = "")
  densities_list[[names_densities_periods]] <- period_densities
  
  # Adding the value of Y density------------------------------------------------------
  densities_y[[paste("Density_yt", i, sep = "")]] <- Y_actual_density

}

# Statistics 

# Combine the vectors into a list
Statitics <- list(
  ATT = ATT,
  MAE = MAE,
  MSE = MSE,
  R2 = R2
)

# AVERAGES---------------------------------------------------------------------------------------------------------------------------------

# Now depending on the number of periods and the number of models so we need to divide for exampel if models are
num_periods = (ending_test_period - starting_test_period) + 1
num_models = length(models_names_act)

# Averages per model
Statistic_averages <- list()

# Statistics list
Statistics_list <- c("ATT", "MAE", "MSE", "R2")

# Loop over Statistics list
for (s in Statistics_list) {
  
  # List averages
  Averages_list <- list()
  
  # Loop over models
  for (mod in models_names_act) {
  
    # Create the name of the variable
    Prefix_average <- paste(s, mod, "average", sep = "_")

    # Initialize mean_per_model for each model
    mean_per_model <- 0

    # Loop over periods
    for (i in 1:num_periods) {
      # Collecting the mean for each model for each period
      stat_value <- get(paste(s, sep = ""))[[i]][[which(models_names_act == mod)]]
      mean_per_model <- mean_per_model + stat_value
    }

    # Calculate the average across all periods for the current model
    mean_per_model <- mean_per_model / num_periods

    # Store the result in Averages_list
    Averages_list[[Prefix_average]] <- mean_per_model
  }
  
  # Store the values
  Statistic_averages[[s]] <- Averages_list
}


################################ ACTUAL OUTPUTS ##############################################

output <- list(
  FitnessStatistics = Statitics,
  average_values = Statistic_averages,
  densities_y = densities_y,
  densities_ML_list = densities_list
)

return(output)

}

Now that we have our dataframe, let’s reshape our ML function so it can work with this new dataframe, and with any dataframe.

MyData2 = nsw.df
X_variables_period = c("educ", "black", "married", "nodegree", "hisp", "age")
y_variable_period = "re"
d_variable_period = "treated" #treatement
CV_num_folds = 10
starting_test_period2 = 78
ending_test_period2 = 78
models <- c("SL.glmnet", "SL.randomForest", "SL.xgboost", "SL.kernelKnn")
models_names <- c("LASSO", "RF", "XgB", "KernelKnn")

Inputs

NSW.results_ML <- ATT_ML_generator_ADVANCED_VF(MyData2, X_variables_period, y_variable_period, d_variable_period, CV_num_folds, starting_test_period2, ending_test_period2, models, models_names)

Results

###### We will also use the averages lists for our purposes

# ATT
ATT_averages_nsw_ML <- data.frame(matrix(unlist(NSW.results_ML$average_values$ATT), nrow = length(NSW.results_ML$average_values$ATT), byrow = TRUE), row.names = names(NSW.results_ML$average_values$ATT))

# MAE
MAE_averages_nsw_ML <- data.frame(matrix(unlist(NSW.results_ML$average_values$MAE), nrow = length(NSW.results_ML$average_values$MAE), byrow = TRUE), row.names = names(NSW.results_ML$average_values$MAE))

# MSE
MSE_averages_nsw_ML <- data.frame(matrix(unlist(NSW.results_ML$average_values$MSE), nrow = length(NSW.results_ML$average_values$MSE), byrow = TRUE), row.names = names(NSW.results_ML$average_values$MSE))

# R2
R2_averages_nsw_ML <- data.frame(matrix(unlist(NSW.results_ML$average_values$R2), nrow = length(NSW.results_ML$average_values$R2), byrow = TRUE), row.names = names(NSW.results_ML$average_values$R2))

# For tha table
Table_nsw_ML <- cbind(ATT_averages_nsw_ML, MAE_averages_nsw_ML, MSE_averages_nsw_ML, R2_averages_nsw_ML)

# Add column names
colnames(Table_nsw_ML) <- c("ATT", "MAE", "MSE", "R2") 

# Add row names
rownames(Table_nsw_ML) <- c(models_names, "JointM")

# Create a code for a LaTeX Table
latex_code_nsw_ML <- xtable(Table_nsw_ML, caption = "ML results per model for the NSW Data")

# Print the LaTeX code
print(latex_code_nsw_ML, include.rownames = T)
% latex table generated in R 4.1.1 by xtable 1.8-4 package
% Mon Mar 11 15:21:58 2024
\begin{table}[ht]
\centering
\begin{tabular}{rrrrr}
  \hline
 & ATT & MAE & MSE & R2 \\ 
  \hline
LASSO & -355.18 & 4606.56 & 38645734.75 & 0.01 \\ 
  RF & -343.75 & 4435.33 & 36355688.58 & 0.08 \\ 
  XgB & -390.55 & 4090.44 & 35754552.17 & 0.12 \\ 
  KernelKnn & -736.94 & 4462.19 & 38040257.09 & 0.04 \\ 
  JointM & -348.39 & 4601.91 & 38585037.33 & 0.01 \\ 
   \hline
\end{tabular}
\caption{ML results per model for the NSW Data} 
\end{table}

Now let’s get some graphics

list_models <- c("Y_actual", models_names, "JointM")

Let’s also get our densities graph to check how well our predicted values fit the actual value Densities

# Values of the densities
ToPlotData_densities_t78 <- data.frame(
  value = c(NSW.results_ML$densities_y$Density_yt78$x, 
            NSW.results_ML$densities_ML_list$t78$LASSO_density$x, 
            NSW.results_ML$densities_ML_list$t78$RF_density$x, 
            NSW.results_ML$densities_ML_list$t78$XgB_density$x,
            NSW.results_ML$densities_ML_list$t78$KernelKnn_density$x,
            NSW.results_ML$densities_ML_list$t78$JointM_density$x),
  density = c(NSW.results_ML$densities_y$Density_yt78$y, 
            NSW.results_ML$densities_ML_list$t78$LASSO_density$y, 
            NSW.results_ML$densities_ML_list$t78$RF_density$y, 
            NSW.results_ML$densities_ML_list$t78$XgB_density$y,
            NSW.results_ML$densities_ML_list$t78$KernelKnn_density$y,
            NSW.results_ML$densities_ML_list$t78$JointM_density$y),
  model = factor(rep(list_models, times = sapply(list(
    NSW.results_ML$densities_y$Density_yt78,
    NSW.results_ML$densities_ML_list$t78$LASSO_density, 
    NSW.results_ML$densities_ML_list$t78$RF_density, 
    NSW.results_ML$densities_ML_list$t78$XgB_density,
    NSW.results_ML$densities_ML_list$t78$KernelKnn_density,
    NSW.results_ML$densities_ML_list$t78$JointM_density
  ), function(d) length(d$x))))
)

# Plot superimposed density curves
ggplot(ToPlotData_densities_t78, aes(x = value, y = density, color = model)) +
  geom_line(linewidth = 0.25) +
  theme_minimal() +
  labs(title = "ML density of the different models predictions and the actual value of real earnings 1978", x = "Values", y = "Density") +
  scale_color_discrete(name = "Model") + 
  coord_cartesian(ylim = c(0, 0.0005) # setting a limit for visualization
                  ) 

# Define the path for the PNG image
Densities_ML_nsw <- "/Users/bonjour/Documents/Master in Economics Bonn/5th semester/Thesis/R-Code/Drafts/13th Draft/Images NSW/Densities_ML_nsw.png"

# Save the ggplot as a PNG image
ggsave(filename = Densities_ML_nsw, plot = last_plot(), width = 8, height = 4, dpi = 300)

NSW.results_DDRD <- drdid_imp_panel(y1 = MyData2$re78, y0 = MyData2$re75, D = MyData2$treated78,
                covariates = cbind(MyData2$educ78, MyData2$black78, MyData2$married78, MyData2$nodegree78, MyData2$hisp78, MyData2$age78))

LET’S MAKE A BOOTSTRAP IN ORDER TO INTEGRATE THE CONFIDENCE INTERVALS TO OUR STUDY

DDRD_nws_ATT <- NSW.results_DDRD$ATT
DDRD_nws_SE <- NSW.results_DDRD$se
DDRD_nws_CI_low <- NSW.results_DDRD$lci
DDRD_nws_CI_up <- NSW.results_DDRD$uci

With these results let’s get our tables of the ATT and other statistics

Let’s begin with the ML results

# Create a data frame with the numeric elements
Table_nsw_DRDD <- cbind(DDRD_nws_ATT, DDRD_nws_CI_low, DDRD_nws_CI_up, DDRD_nws_SE)

# Add column names
colnames(Table_nsw_DRDD) <- c("ATT", "ATT_lowerCI", "ATT_upperCI", "SE") 

# Add row names
rownames(Table_nsw_DRDD) <- "value"

# Create a code for a LaTeX Table
latex_code_nsw_DRDD <- xtable(Table_nsw_DRDD, caption = "DRDD results per model for the NSW Data")

# Print the LaTeX code
print(latex_code_nsw_DRDD, include.rownames = TRUE)
% latex table generated in R 4.1.1 by xtable 1.8-4 package
% Mon Mar 11 15:23:29 2024
\begin{table}[ht]
\centering
\begin{tabular}{rrrrr}
  \hline
 & ATT & ATT\_lowerCI & ATT\_upperCI & SE \\ 
  \hline
value & 948.87 & -228.36 & 2126.10 & 600.63 \\ 
   \hline
\end{tabular}
\caption{DRDD results per model for the NSW Data} 
\end{table}

Let’s get a nice table out of it

# Install and load the plm package
install.packages("plm")
Error in install.packages : Updating loaded packages
library(plm)

Let’s recover the confidence intervals

# Load the Wages dataset
data("Produc")
Produc

Now a nice graph

Produc <- Produc[, !(names(Produc) %in% c("region"))]
Produc

Now let’s calculate the length per model and the times the ATT average value falls within this interval

Produc <- Produc[!(Produc$year %in% c(seq(1972, 1986))), ]
Produc

A table

library(tidyr)

What would the results be for the DRDD estimator?

Product_df <- pivot_wider(Produc, 
                           id_cols = state,
                           names_from = year,
                           values_from = c(pcap, hwy, water, util, pc, gsp, emp, unemp))
Product_df

5th period results

Product_df$treatment_1970 <- 0
Product_df$treatment_1971 <- sample(c(0, 1), nrow(Product_df), replace = TRUE)
Product_df

Creating the table and saving the image

MyData3 = Product_df
X_variables_period3 = c("pcap_", "hwy_", "water_", "util_", "pc_", "emp_", "unemp_")
y_variable_period3 = "gsp_"
d_variable_period3 = "treatment_"
CV_num_folds3 = 4 # as we have 48 observations, then 4 folds with 12 observations
starting_test_period3 = 1971
ending_test_period3 = 1971
models <- c("SL.glmnet", "SL.randomForest", "SL.xgboost", "SL.kernelKnn")
models_names <- c("LASSO", "RF", "XgB", "KernelKnn")

Now let’s work with the DRDD - Bootstrap: No need

Produc.results_ML <- ATT_ML_generator_ADVANCED_VF(MyData3, X_variables_period3, y_variable_period3, d_variable_period3, CV_num_folds3, starting_test_period3, ending_test_period3, models, models_names)
Warning: Option grouped=FALSE enforced in cv.glmnet, since < 3 observations per fold
Warning: Option grouped=FALSE enforced in cv.glmnet, since < 3 observations per fold
Warning: Option grouped=FALSE enforced in cv.glmnet, since < 3 observations per fold
Warning: Option grouped=FALSE enforced in cv.glmnet, since < 3 observations per fold
Warning: Option grouped=FALSE enforced in cv.glmnet, since < 3 observations per fold
Warning: Option grouped=FALSE enforced in cv.glmnet, since < 3 observations per fold
Warning: Option grouped=FALSE enforced in cv.glmnet, since < 3 observations per fold
Warning: Option grouped=FALSE enforced in cv.glmnet, since < 3 observations per fold
Warning: Option grouped=FALSE enforced in cv.glmnet, since < 3 observations per fold
Warning: Option grouped=FALSE enforced in cv.glmnet, since < 3 observations per fold

Now let’s do a beautiful last table

###### We will also use the averages lists for our purposes

# ATT
ATT_averages_produc_ML <- data.frame(matrix(unlist(Produc.results_ML$average_values$ATT), nrow = length(Produc.results_ML$average_values$ATT), byrow = TRUE), row.names = names(Produc.results_ML$average_values$ATT))

# MAE
MAE_averages_produc_ML <- data.frame(matrix(unlist(Produc.results_ML$average_values$MAE), nrow = length(Produc.results_ML$average_values$MAE), byrow = TRUE), row.names = names(Produc.results_ML$average_values$MAE))

# MSE
MSE_averages_produc_ML <- data.frame(matrix(unlist(Produc.results_ML$average_values$MSE), nrow = length(Produc.results_ML$average_values$MSE), byrow = TRUE), row.names = names(Produc.results_ML$average_values$MSE))

# R2
R2_averages_produc_ML <- data.frame(matrix(unlist(Produc.results_ML$average_values$R2), nrow = length(Produc.results_ML$average_values$R2), byrow = TRUE), row.names = names(Produc.results_ML$average_values$R2))

# For tha table
Table_produc_ML <- cbind(ATT_averages_produc_ML, MAE_averages_produc_ML, MSE_averages_produc_ML, R2_averages_produc_ML)

# Add column names
colnames(Table_produc_ML) <- c("ATT", "MAE", "MSE", "R2") 

# Add row names
rownames(Table_produc_ML) <- c(models_names, "JointM")

# Create a code for a LaTeX Table
latex_code_produc_ML <- xtable(Table_produc_ML, caption = "ML results per model for the Produc Data")

# Print the LaTeX code
print(latex_code_produc_ML, include.rownames = T)
% latex table generated in R 4.1.1 by xtable 1.8-4 package
% Mon Mar 11 15:29:50 2024
\begin{table}[ht]
\centering
\begin{tabular}{rrrrr}
  \hline
 & ATT & MAE & MSE & R2 \\ 
  \hline
LASSO & -2253.35 & 4181.62 & 78215450.49 & 0.99 \\ 
  RF & -6456.99 & 9894.95 & 701132411.28 & 0.84 \\ 
  XgB & -5387.02 & 21599.13 & 1747873452.64 & 0.48 \\ 
  KernelKnn & -17923.82 & 20093.65 & 2023363877.38 & 0.75 \\ 
  JointM & -2253.35 & 4181.62 & 78215450.49 & 0.99 \\ 
   \hline
\end{tabular}
\caption{ML results per model for the Produc Data} 
\end{table}
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OgogIHBkZl9kb2N1bWVudDogZGVmYXVsdAogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBudW1iZXJfc2VjdGlvbnM6IHRydWUKLS0tCgojIyBTRVRVUCBGT1IgT1VSIFBST0pFQ1QKCmBgYHtyfQojIyMgQ3VzdG9tIExpYnJhcnkKY3VzdG9tX2xpYnJhcnlfcGF0aCA8LSAiL1VzZXJzL2JvbmpvdXIvRG9jdW1lbnRzL01hc3RlciBpbiBFY29ub21pY3MgQm9ubi81dGggc2VtZXN0ZXIvVGhlc2lzL1ItQ29kZS9Ucnkgd2l0aCBEZVNvdXphIENvZGUvUGFja2FnZXMiCgojIyMgRnVuY3Rpb24gdG8gY2hlY2sgaWYgYWxsIHJlcXVpcmVkIHBhY2thZ2VzIGFyZSBpbnN0YWxsZWQgYW5kIGxvYWRlZApwYWNrYWdlQ2hlY2sgPSBmdW5jdGlvbih4KSB7CiAgIyBTdG9yZSBvcmlnaW5hbCBsaWJyYXJ5IHBhdGhzCiAgb3JpZ2luYWxfbGlicGF0aHMgPC0gLmxpYlBhdGhzKCkKCiAgIyBTZXQgY3VzdG9tIGxpYnJhcnkgcGF0aAogIC5saWJQYXRocyhjKGN1c3RvbV9saWJyYXJ5X3BhdGgsIC5saWJQYXRocygpKSkKCiAgIyBDaGVjayBhbmQgaW5zdGFsbCBwYWNrYWdlCiAgaWYgKCFyZXF1aXJlKHgsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSwgcXVpZXRseSA9IFRSVUUpKSB7CiAgICBpbnN0YWxsLnBhY2thZ2VzKHgsIGRlcGVuZGVuY2llcyA9IFRSVUUsIHJlcG9zID0gImh0dHBzOi8vZnRwLnVzc2cuaXUuZWR1L0NSQU4vIikKICAgIGxpYnJhcnkoeCwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKQogIH0KCiAgIyBSZXN0b3JlIG9yaWdpbmFsIGxpYnJhcnkgcGF0aHMKICAubGliUGF0aHMob3JpZ2luYWxfbGlicGF0aHMpCn0KCiMgImJhcnRNYWNoaW5lIiwgImtubiIsICJsZWVrYXNzbyIsICJsb2dyZWciLCAic3BlZWRsbSIsICJzdGVwLmludGVyYWN0aW9uIiwgInRlbXBsYXRlIiwgImJheWVzZ2xtIiwgImNhcmV0LnJwYXJ0IiwgImV4dHJhVHJlZXMiLCAiZ2xtIiwgImlwcmVkYmFnZyIKIyAia3N2bSIsICJsbSIsICJtZWFuIiwgInBvbHltYXJzIiwgInJwYXJ0UHJ1bmUiLCAic3RlcCIsICJzdGVwQUlDIiwgImNmb3Jlc3QiLCAiZ2xtLmludGVyYWN0aW9uIiwgImxvZXNzIiwgInFkYSIsIHN0ZXAuZm9yd2FyZCIsICJzdm0iCgojIyBUeXBlIGluIHRoZSBwYWNrYWdlcyB5b3UgbmVlZCBiZWxvdwpwa2cgPC0gYygiU3VwZXJMZWFybmVyIiwgImdncGxvdDIiLCAiUmhwY0JMQVNjdGwiLCJjYXJldCIsICJkYXRhLnRhYmxlIiwgIk1ldHJpY3MiLCAia25pdHIiLCAia2FibGVFeHRyYSIsICJ3ZWJzaG90IiwgInByb2Nlc3N4IiwgIm1hZ2ljayIsICJnbG1uZXQiLCAicmFuZG9tRm9yZXN0IiwgImNhcmV0IiwgImVhcnRoIiwgImdibSIsICJubmxzIiwgInJwYXJ0IiwgInJhbmdlciIsICJiaWdsYXNzbyIsICJnYW0iLCAiS2VybmVsS25uIiwgImxkYSIsICJubmV0IiwgInJpZGdlIiwgInNwZWVkZ2xtIikKc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxhcHBseShwa2csIHBhY2thZ2VDaGVjaykpCiMgSW5zdGFsbCB4Z2Jvb3N0Cmluc3RhbGwucGFja2FnZXMoInhnYm9vc3QiLCByZXBvcz1jKCJodHRwOi8vZG1sYy5tbC9kcmF0LyIsIGdldE9wdGlvbigicmVwb3MiKSksIHR5cGU9InNvdXJjZSIpCiMgSW5zdGFsbCBQaGFudG9tSlMgd2hpY2ggd2Vic2hvdCB1c2VzCndlYnNob3Q6Omluc3RhbGxfcGhhbnRvbWpzKCkKCgojIFBhY2thZ2UgZm9yIERSREQKcmVtb3Rlczo6aW5zdGFsbF9naXRodWIoInBlZHJvaGNncy9EUkRJRCIpCgojIEZvciB0YWJsZXMgaW4gTEFURVggY29kZQppbnN0YWxsLnBhY2thZ2VzKCJ4dGFibGUiKQoKIyBQYWNrYWdlIGZvciBncmFwaHMKaW5zdGFsbC5wYWNrYWdlcygiZHBseXIiKQppbnN0YWxsLnBhY2thZ2VzKCJ0aWR5ciIpCmluc3RhbGwucGFja2FnZXMoInB1cnJyIikKCmluc3RhbGwucGFja2FnZXMoInBzeWNoIikKYGBgCgpgYGB7cn0KIyBDYWxsaW5nIGFsbCBvdXIgcGFja2FnZXMKbGlicmFyeShTdXBlckxlYXJuZXIpICMgZm9yIE1MCmxpYnJhcnkoZ2dwbG90MikgIyBmb3IgZ3JhcGhzCmxpYnJhcnkoUmhwY0JMQVNjdGwpCmxpYnJhcnkoY2FyZXQpCmxpYnJhcnkoZGF0YS50YWJsZSkgCmxpYnJhcnkoTWV0cmljcykgIyBmb3IgbWV0cmljcwpsaWJyYXJ5KGtuaXRyKSAjIGZvciB0YWJsZXMKbGlicmFyeShrYWJsZUV4dHJhKSAjIGZvciBzYXZpbmcgaW1hZ2VzCmxpYnJhcnkod2Vic2hvdCkgIyBmb3Igc2F2aW5nIGltYWdlcwpsaWJyYXJ5KE1BU1MpCmxpYnJhcnkobWFnaWNrKSAjIEhpZ2ggcXVhbGl0eSBpbWFnZXMKCiMgTUFDSElORSBMRUFSTklORyBQQUNLQUdFUwpsaWJyYXJ5KGdsbW5ldCkgIyBmb3IgTUwgMQpsaWJyYXJ5KHJhbmRvbUZvcmVzdCkgIyBmb3IgTUwgMgpsaWJyYXJ5KHhnYm9vc3QpICMgZm9yIE1MIDMKI2xpYnJhcnkoYmFydE1hY2hpbmUpICMgZm9yIE1MIDQKbGlicmFyeShjYXJldCkgIyBmb3IgTUwgNQpsaWJyYXJ5KGVhcnRoKSAjIGZvciBNTCA2CmxpYnJhcnkoZ2JtKSAjIGZvciBNTCA3CiNsaWJyYXJ5KGtubikgIyBmb3IgTUwgOAojbGlicmFyeShsZWVrYXNzbykgIyBmb3IgTUwgOQojbGlicmFyeShsb2dyZWcpICMgZm9yIE1MIDEwCmxpYnJhcnkobm5scykgIyBmb3IgTUwgMTEKbGlicmFyeShycGFydCkgIyBmb3IgTUwgMTIKI2xpYnJhcnkoc3BlZWRsbSkgIyBmb3IgTUwgMTMKI2xpYnJhcnkoc3RlcC5pbnRlcmFjdGlvbikgIyBmb3IgTUwgMTQKI2xpYnJhcnkodGVtcGxhdGUpICMgZm9yIE1MIDE1CiNsaWJyYXJ5KGJheWVzZ2xtKSAjIGZvciBNTCAxNgojbGlicmFyeShjYXJldC5ycGFydCkgIyBmb3IgTUwgMTcKI2xpYnJhcnkoZXh0cmFUcmVlcykgIyBmb3IgTUwgMTgKI2xpYnJhcnkoZ2xtKSAjIGZvciBNTCAxOQojbGlicmFyeShpcHJlZGJhZ2cpICMgZm9yIE1MIDIwCiNsaWJyYXJ5KGtzdm0pICMgZm9yIE1MIDIxCiNsaWJyYXJ5KGxtKSAjIGZvciBNTCAyMgojbGlicmFyeShtZWFuKSAjIGZvciBNTCAyMwojbGlicmFyeShwb2x5bWFycykgIyBmb3IgTUwgMjQKbGlicmFyeShyYW5nZXIpICMgZm9yIE1MIDI1CiNsaWJyYXJ5KHJwYXJ0UHJ1bmUpICMgZm9yIE1MIDI2CiNsaWJyYXJ5KHN0ZXApICMgZm9yIE1MIDI3CiNsaWJyYXJ5KHN0ZXBBSUMpICMgZm9yIE1MIDI4CmxpYnJhcnkoYmlnbGFzc28pICMgZm9yIE1MIDI5CiNsaWJyYXJ5KGNmb3Jlc3QpICMgZm9yIE1MIDMwCmxpYnJhcnkoZ2FtKSAjIGZvciBNTCAzMQojbGlicmFyeShnbG0uaW50ZXJhY3Rpb24pICMgZm9yIE1MIDMyCmxpYnJhcnkoS2VybmVsS25uKSAjIGZvciBNTCAzMwpsaWJyYXJ5KGxkYSkgIyBmb3IgTUwgMzQKI2xpYnJhcnkobG9lc3MpICMgZm9yIE1MIDM1CmxpYnJhcnkobm5ldCkgIyBmb3IgTUwgMzYKI2xpYnJhcnkocWRhKSAjIGZvciBNTCAzNwpsaWJyYXJ5KHJpZGdlKSAjIGZvciBNTCAzOApsaWJyYXJ5KHNwZWVkZ2xtKSAjIGZvciBNTCAzOQojbGlicmFyeShzdGVwLmZvcndhcmQpICMgZm9yIE1MIDM4CiNsaWJyYXJ5KHN2bSkgIyBmb3IgTUwgMzkKCgojIERSREQKbGlicmFyeShEUkRJRCkKCgojIEZvciB0YWJsZXMgaW4gTEFURVggY29kZQpsaWJyYXJ5KHh0YWJsZSkKCiMgUGFja2FnZSBmb3IgZ3JhcGhzCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkocHVycnIpCmxpYnJhcnkodGlkeXIpCgpsaWJyYXJ5KHBzeWNoKQpgYGAKCiMjIEZJUlNUIFBBUlQgSVMgQ1JFQVRJTkcgVEhFIFNJTVVMQVRFRCBEQVRBIEJBU0UKCkRlZmluZSB0aGUgcGFyYW1ldGVycwpgYGB7cn0Kc2V0LnNlZWQoMSkKCiMgUGFyYW1ldGVycwoKbiA8LSAxMDAwICNpbmRpdmlkdWFscwpiZXRhLmQgPC0gYygwLjMsIDAuNCwgMC41KSAjIGJldGEgImQiIGZvciAzIGRpZmZlcmVudCBwZXJpb2RzCmJldGEudHJ1ZSA8LSBtYXRyaXgoYygtMC41LDAuMSwwLjUsMC41LC0wLjUsCiAgICAgICAgICAgICAgICAgICAgICAtMC42LDAuMiwwLjYsMC41LC0wLjUsCiAgICAgICAgICAgICAgICAgICAgICAtMC44LDAuNCwwLjYsMC45LC0wLjgsCiAgICAgICAgICAgICAgICAgICAgICAtMC44LDAuNSwwLjcsMC45LC0xLjAsCiAgICAgICAgICAgICAgICAgICAgICAtMC45LDAuNywwLjcsMS4wLC0xLjApLG5yb3c9IDUsIG5jb2w9IDUsIGJ5cm93PVRSVUUpICMgYmV0YXMgIlgiIGZvciA1IGRpZmZlcmVudCBwZXJpb2RzCnNpZ21hIDwtIG1hdHJpeChjKDEsMC4xLDAuMSwwLjEsMC4xLAogICAgICAgICAgICAgICAgICAwLjEsMiwwLjEsMC4xLDAuMSwKICAgICAgICAgICAgICAgICAgMC4xLDAuMSwzLDAuMSwwLjEsCiAgICAgICAgICAgICAgICAgIDAuMSwwLjEsMC4xLDQsMC4xLAogICAgICAgICAgICAgICAgICAwLjEsMC4xLDAuMSwwLjEsNSkgLG5yb3c9IDUsIG5jb2w9IDUsIGJ5cm93PVRSVUUpICMgd2Ugd2lsbCBrZWVwIHRoZSBzYW1lIHZhcmlhbmNlIHRocm91Z2ggdGltZQptdSA8LSByZXAoMCw1KSAjIHRoZSBtZWFuIHdpbGwgYmUgemVybyB0aHJvdWdoIHRpbWUKcHJvYmFiaWxpdHkgPC0gMC41ICAjCmBgYAoKRGVmaW5lIHRoZSBkYXRhIGdlbmVyYXRpbmcgcHJvY2VzcwpgYGB7cn0KIyBEYXRhIGdlbmVyYXRvcgoKZGF0YS5nZW5lcmF0b3IgPC0gZnVuY3Rpb24obiwgc2lnbWEsIG11LCBiZXRhLnRydWUsIGJldGEuZCwgcHJvYmFiaWxpdHkpewogIAogICMgWHMgYW5kIGVycm9ycyBmb3IgNSBwZXJpb2RzCiAgCiAgIyBDcmVhdGUgYW4gZW1wdHkgbGlzdCB0byBzdG9yZSB0aGUgdmVjdG9ycwogIHhfdF9saXN0IDwtIGxpc3QoKQogIGVfdF9saXN0IDwtIGxpc3QoKQogIAogICMgR2VuZXJhdGUgdGhlIHZlY3RvcnMgd2l0aGluIHRoZSBsb29wIGFuZCBzdG9yZSB0aGVtIGluIHRoZSBsaXN0IHdpdGggdGhlaXIgcmVzcGVjdGl2ZSB0aW1lcwogIGZvciAoaSBpbiAxOjUpIHsKICAgIHhfdGkgPC0gbXZybm9ybShuLCBtdSwgc2lnbWEpCiAgICB4X3RfbGlzdFtbcGFzdGUwKCJ4X3QiLCBpKV1dIDwtIHhfdGkKICAgIGVfdGkgPC0gcm5vcm0obiwgMCwgc3FydCgxMCkpCiAgICBlX3RfbGlzdFtbcGFzdGUwKCJlX3QiLCBpKV1dIDwtIGVfdGkKICB9CgogICMgR2VuZXJhdGUgdGhlIGQgZm9yIDUgcGVyaW9kcwogIGRfdDEgPC0gcmVwKDAsIG4pCiAgZF90MiA8LSByZXAoMCwgbikKICBkX3QzIDwtIHNhbXBsZShjKDAsIDEpLCBzaXplID0gbiwgcmVwbGFjZSA9IFRSVUUpCiAgZF90NCA8LSBpZmVsc2UoZF90MyA9PSAxIHwgcnVuaWYobGVuZ3RoKGRfdDMpKSA8IHByb2JhYmlsaXR5LCAxLCAwKQogIGRfdDUgPC0gaWZlbHNlKGRfdDQgPT0gMSB8IHJ1bmlmKGxlbmd0aChkX3Q0KSkgPCBwcm9iYWJpbGl0eSwgMSwgMCkKICBkIDwtIGNiaW5kKGRfdDEsIGRfdDIsIGRfdDMsIGRfdDQsIGRfdDUpCiAgCiAgIyBHZW5lcmF0ZSB0aGUgeXMgLS0tLS0tLS0tLS0tLS0KICAKICAjIEJlZm9yZSB0cmVhdG1lbnQKICB5X3QxIDwtIHhfdF9saXN0W1sieF90MSJdXSAlKiUgYmV0YS50cnVlWywxXSArIGVfdF9saXN0W1siZV90MSJdXQogIHlfdDIgPC0geF90X2xpc3RbWyJ4X3QyIl1dICUqJSBiZXRhLnRydWVbLDJdICsgZV90X2xpc3RbWyJlX3QyIl1dCiAgIyBBZnRlciB0cmVhdG1lbnQKICB5X3QzIDwtIGRfdDMqYmV0YS5kWzFdICsgeF90X2xpc3RbWyJ4X3QzIl1dICUqJSBiZXRhLnRydWVbLDNdICsgZV90X2xpc3RbWyJlX3QzIl1dCiAgeV90NCA8LSBkX3QzKmJldGEuZFsyXSArIHhfdF9saXN0W1sieF90NCJdXSAlKiUgYmV0YS50cnVlWyw0XSArIGVfdF9saXN0W1siZV90NCJdXQogIHlfdDUgPC0gZF90MypiZXRhLmRbM10gKyB4X3RfbGlzdFtbInhfdDUiXV0gJSolIGJldGEudHJ1ZVssNV0gKyBlX3RfbGlzdFtbImVfdDUiXV0KICB5IDwtIGNiaW5kKHlfdDEsIHlfdDIsIHlfdDMsIHlfdDQsIHlfdDUpCiAgCiAgI1N0YW5kYXJkaXplIFhzCiAgCiAgIyBJbml0aWFsaXplIHRoZSBsaXN0IHRvIHN0b3JlIHN0YW5kYXJkaXplZCBtYXRyaWNlcwogIHhfdF9saXN0LnNkIDwtIGxpc3QoKQogIAogIGZvciAodmFyaWFibGUgaW4gbmFtZXMoeF90X2xpc3QpKSB7CiAgICAjRGVmaW5pbmcgdGhlIG1hdHJpY2VzCiAgICB4X3RfbGlzdC5zZFtbcGFzdGUwKHZhcmlhYmxlLCAiLnNkIildXSA8LSBtYXRyaXgoTkEsIG5yb3cgPSBucm93KHhfdF9saXN0W1t2YXJpYWJsZV1dKSwgbmNvbCA9IG5jb2woeF90X2xpc3RbW3ZhcmlhYmxlXV0pKQogICAgI1N0YXJ0aW5nIHRoZSBzdGFuZGFyZGl6YXRpb24KICAgIGZvciAoaSBpbiAxOm5jb2woeF90X2xpc3Quc2RbW3Bhc3RlMCh2YXJpYWJsZSwgIi5zZCIpXV0pKXsKICAgIHhfdF9saXN0LnNkW1twYXN0ZTAodmFyaWFibGUsICIuc2QiKV1dWywgaV0gPC0gKHhfdF9saXN0W1t2YXJpYWJsZV1dWywgaV0gLSBtZWFuKHhfdF9saXN0W1t2YXJpYWJsZV1dWywgaV0pKSAvIHNkKHhfdF9saXN0W1t2YXJpYWJsZV1dWywgaV0pCiAgICB9CiAgfQogIAogIGRhdGEgPC0gZGF0YS5mcmFtZSAoInkiID0geSwgImQiID0gZCwgIngiID0geF90X2xpc3QsICJ4LnNkIiA9IHhfdF9saXN0LnNkKQogIHJldHVybihkYXRhKQp9CmBgYAoKR2VuZXJhdGUgdGhlIGRhdGEgc2V0CmBgYHtyfQojIFdlIGNhbiBtYWtlIGdlbmVyYXRlIGEgZGF0YSBzZXQKTXlEYXRhIDwtIGRhdGEuZ2VuZXJhdG9yKG4sIHNpZ21hLCBtdSwgYmV0YS50cnVlLCBiZXRhLmQsIHByb2JhYmlsaXR5KQpgYGAKCiMgQURWQU5DRUQgRlVOQ1RJT04gVE8gUkVDT1ZFUiBUSEUgQVRULCBNQUUsIE1TRSwgUjIgQU5EIFRIRSBERU5TSVRJRVMgLSBNQUNISU5FIExFQVJOSU5HCgpGdW5jdGlvbgpgYGB7cn0KQVRUX01MX2dlbmVyYXRvcl9BRFZBTkNFRCA8LSBmdW5jdGlvbihNeURhdGEsIENWX251bV9mb2xkcywgc3RhcnRpbmdfdGVzdF9wZXJpb2QsIGVuZGluZ190ZXN0X3BlcmlvZCwgbW9kZWxzLCBtb2RlbHNfbmFtZXMpewoKIyBUaGlzIHZlY3RvciB3aWxsIHN0b3JlIG15IGRlbnNpdGllcwpkZW5zaXRpZXNfbGlzdCA8LSBsaXN0KCkKCiMgVG8gc3RvcmUgdGhlIHkgZGVuc2l0aWVzCmRlbnNpdGllc195IDwtIGxpc3QoKQoKIyBEZWZpbmUgdGhlIG1vZGVsIG5hbWVzIGFjdHVhbCB2YWx1ZQptb2RlbHNfbmFtZXNfYWN0IDwtIGMobW9kZWxzX25hbWVzLCAiSm9pbnRNIikKCiMgRGVmaW5lIGxpc3RzCk1BRSA8LSBsaXN0KCkKTVNFIDwtIGxpc3QoKQpSMiA8LSBsaXN0KCkKQVRUIDwtIGxpc3QoKQoKIyBDb21wbGV0ZSBkYXRhIGZvciBwZXJpb2RzIDMgLSA1Cgpmb3IgKGkgaW4gc3RhcnRpbmdfdGVzdF9wZXJpb2Q6ZW5kaW5nX3Rlc3RfcGVyaW9kKXsKICAKICAjIENyZWF0ZSB2YXJpYWJsZSBuYW1lcyBiYXNlZCBvbiB0aGUgbG9vcCBpbmRleAogIHhfcHJlZml4IDwtIHBhc3RlKCJ4LnhfdCIsIGksIHNlcCA9ICIiKQogIGRfcHJlZml4IDwtIHBhc3RlKCJkLmRfdCIsIGksIHNlcCA9ICIiKQogIHlfcHJlZml4IDwtIHBhc3RlKCJ5LiIsIGksIHNlcCA9ICIiKQogIERhdGFfY29tcGxldGVYX3ByZWZpeCA8LSBwYXN0ZSgiRGF0YV9jb21wbGV0ZV9YdCIsIGksIHNlcCA9ICIiKQogIERhdGFfY29tcGxldGVZX3ByZWZpeCA8LSBwYXN0ZSgiRGF0YV9jb21wbGV0ZV9ZdCIsIGksIHNlcCA9ICIiKQogIAogICMgQ29tcGxldGUgdGhlIG9uZSBmb3IgWAogIHhfdmFyaWFibGVzIDwtIHBhc3RlKHhfcHJlZml4LCAxOjUsIHNlcCA9ICIuIikKICAKICAjIFN1YnNldCB0aGUgZGF0YSBiYXNlZCBvbiB0aGUgY29uc3RydWN0ZWQgdmFyaWFibGUgbmFtZXMKICBzdWJzZXRfZGF0YV94IDwtIHN1YnNldChNeURhdGEsIHNlbGVjdCA9IGMoZF9wcmVmaXgsIHhfdmFyaWFibGVzKSkKICBhc3NpZ24oRGF0YV9jb21wbGV0ZVhfcHJlZml4LCBhcy5kYXRhLmZyYW1lKHN1YnNldF9kYXRhX3gpKSAjIFggYXMgZGF0YWZyYW1lCiAgCiAgIyBTdWJzZXQgYW5kIGFzc2lnbiBZCiAgYXNzaWduKERhdGFfY29tcGxldGVZX3ByZWZpeCwgTXlEYXRhW1t5X3ByZWZpeF1dKSAjIFkKICAKICAjIE5vdyBsZXQncyBnZXQgdGhlIGFjdHVhbCB2YWx1ZXMgb2YgRGF0YV9jb21wbGV0ZVhfcHJlZml4IGFuZCBEYXRhX2NvbXBsZXRlWV9wcmVmaXggZm9yIGxhdGVyIHVzYWdlCiAgRGF0YV9jb21wbGV0ZVhfYWN0dWFsIDwtIGdldChEYXRhX2NvbXBsZXRlWF9wcmVmaXgpCiAgRGF0YV9jb21wbGV0ZVlfYWN0dWFsIDwtIGdldChEYXRhX2NvbXBsZXRlWV9wcmVmaXgpCiAgCiAgIyBMZXQncyBhbHNvIGdldCB0aGUgZGVuc2l0eSBmbyBBY3R1YWwgWSBqdXN0IGZvciBsYXRlciAtLS0tLQogIAogICMgQ3JlYXRlIHRoZSB2YXJpYWJsZSBmb3IgdGhlIGRlbnNpdHkKICBZX0RlbnNpdHlfQ29tcGxldGUgPC0gcGFzdGUoIkRlbnNpdHlfIiwgRGF0YV9jb21wbGV0ZVlfcHJlZml4LCBzZXAgPSAiIikKICAKICAjIEFzc2lnbiB0aGUgdmFsdWVzIG9mIHRoZSB2YXJpYWJsZXMKICBhc3NpZ24oWV9EZW5zaXR5X0NvbXBsZXRlLCBkZW5zaXR5KERhdGFfY29tcGxldGVZX2FjdHVhbCkpCiAgCiAgIyBTdG9yZSB0aGUgdmFsdWVzIGZvciB1c2FnZSBpbnNpZGUgdGhlIGxvb3Agb2YgdGhlIFkgZGVuc2l0eQogIFlfZGVuc2l0eSA8LSBnZXQoWV9EZW5zaXR5X0NvbXBsZXRlKQogIAogICMgVFJBSU4gREFUQSBGT1IgQUxMIFBFUklPRFMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogIAogICMgRGF0YSB0byBUcmFpbgogIERhdGFfdG9UcmFpbl9wcmVmaXggPC0gcGFzdGUoIkRhdGFfdG9UcmFpbl90IiwgaSwgc2VwID0gIiIpCiAgCiAgIyBDcmVhdGUgdmFyaWFibGUgbmFtZXMgYmFzZWQgb24gdGhlIGxvb3AgaW5kZXgKICBUcmFpbl94X3ByZWZpeCA8LSBwYXN0ZSgiVHJhaW5feF90IiwgaSwgc2VwID0gIiIpCiAgVHJhaW5feV9wcmVmaXggPC0gcGFzdGUoIlRyYWluX3lfdCIsIGksIHNlcCA9ICIiKQogIAogICMgU3Vic2V0IHRoZSBkYXRhIGJhc2VkIG9uIHRoZSBjb25zdHJ1Y3RlZCB2YXJpYWJsZSBuYW1lcwogIERhdGFfdG9UcmFpbl9zdWJzZXQgPC0gc3Vic2V0KE15RGF0YSwgTXlEYXRhW1tkX3ByZWZpeF1dID09IDApCiAgYXNzaWduKERhdGFfdG9UcmFpbl9wcmVmaXgsIERhdGFfdG9UcmFpbl9zdWJzZXQpICMgRGF0YSB0byB0cmFpbgogIGFzc2lnbihUcmFpbl94X3ByZWZpeCwgYXMuZGF0YS5mcmFtZShzdWJzZXQoRGF0YV90b1RyYWluX3N1YnNldCwgc2VsZWN0ID0gYyhkX3ByZWZpeCwgeF92YXJpYWJsZXMpKSkpICMgWAogIGFzc2lnbihUcmFpbl95X3ByZWZpeCwgRGF0YV90b1RyYWluX3N1YnNldFtbeV9wcmVmaXhdXSkgIyBZCiAgCiAgIyBIT0xEIERBVEEgRk9SIEFMTCBQRVJJT0RTLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgCiAgIyBEYXRhIHRvIFRyYWluCiAgRGF0YV90b0hvbGRfcHJlZml4IDwtIHBhc3RlKCJEYXRhX3RvSG9sZF90IiwgaSwgc2VwID0gIiIpCiAgCiAgIyBDcmVhdGUgdmFyaWFibGUgbmFtZXMgYmFzZWQgb24gdGhlIGxvb3AgaW5kZXgKICBIb2xkX3hfcHJlZml4IDwtIHBhc3RlKCJIb2xkX3hfdCIsIGksIHNlcCA9ICIiKQogIEhvbGRfeV9wcmVmaXggPC0gcGFzdGUoIkhvbGRfeV90IiwgaSwgc2VwID0gIiIpCiAgCiAgIyBTdWJzZXQgdGhlIGRhdGEgYmFzZWQgb24gdGhlIGNvbnN0cnVjdGVkIHZhcmlhYmxlIG5hbWVzCiAgRGF0YV90b0hvbGRfc3Vic2V0IDwtIHN1YnNldChNeURhdGEsIE15RGF0YVtbZF9wcmVmaXhdXSA9PSAxKQogIGFzc2lnbihEYXRhX3RvSG9sZF9wcmVmaXgsIERhdGFfdG9Ib2xkX3N1YnNldCkgIyBEYXRhIHRvIGhvbGQKICBhc3NpZ24oSG9sZF94X3ByZWZpeCwgYXMuZGF0YS5mcmFtZShzdWJzZXQoRGF0YV90b0hvbGRfc3Vic2V0LCBzZWxlY3QgPSBjKGRfcHJlZml4LCB4X3ZhcmlhYmxlcykpKSkgIyBYCiAgYXNzaWduKEhvbGRfeV9wcmVmaXgsIERhdGFfdG9Ib2xkX3N1YnNldFtbeV9wcmVmaXhdXSkgIyBZCiAgCiAgIyBMRVQnUyBVU0UgT1VSIE1BQ0hJTkUgTEVBUk5JTkcgTU9ERUxTIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgCiAgIyMgRGVmaW5lIHRoZSBudW1iZXIgb2Ygc3ViZGF0YSBzcGxpdHMgZm9yIHRoZSBDcm9zcy1WYWxpZGF0aW9uCiAgY29udHJvbCA8LSBTdXBlckxlYXJuZXIuQ1YuY29udHJvbChWID0gQ1ZfbnVtX2ZvbGRzKQoKICAgIyBEZWZpbmUgdGhlIHZlY3RvciB0aGF0IHdpbGwgc3RvcmUgbXkgbW9kZWxzCiAgbW9kZWxzX3VzZSA8LSBjKCkgIyBlbXB0eSBieSBub3cKICAKICAjIFRoZW4gdGhlIGxvb3AgCiAgZm9yIChqIGluIHNlcV9hbG9uZyhtb2RlbHMpKSB7CiAgICAKICAgICAgIyBDcmVhdGUgdGhlIHZhcmlhYmxlcyBuYW1lcwogICAgICBtb2RlbF9uYW1lX3ByZWZpeCA8LSBwYXN0ZShtb2RlbHNfbmFtZXNbal0sICJfdCIsIGksIHNlcCA9ICIiKQoKICAgICAgIyBTZXQgdGhlIHNlZWQKICAgICAgc2V0LnNlZWQoMSkKICAgICAgCiAgICAgICMgVXNlIHRoZSBtb2RlbCBuYW1lIGluIHRoZSBTdXBlckxlYXJuZXIgZnVuY3Rpb24KICAgICAgYXNzaWduKG1vZGVsX25hbWVfcHJlZml4LCBTdXBlckxlYXJuZXIoWSA9IGdldChUcmFpbl95X3ByZWZpeCksIFggPSBnZXQoVHJhaW5feF9wcmVmaXgpLCBmYW1pbHkgPSBnYXVzc2lhbigpLCBTTC5saWJyYXJ5ID0gbW9kZWxzW2pdLCBjdkNvbnRyb2wgPSBjb250cm9sKSkKICAgICAgCiAgICAgICMgQWRkIGVsZW1lbnRzIHRvcCB0aGUgbW9kZWxzX3VzZQogICAgICBtb2RlbHNfdXNlIDwtIGMobW9kZWxzX3VzZSwgbW9kZWxfbmFtZV9wcmVmaXgpCiAgfQogIAogICMgRGVmaW5pbmcgdGhlIGpvaW50IG1vZGVsCiAgSm9pbnRNX3ByZWZpeCA8LSBwYXN0ZSgiSm9pbnRNX3QiLCBpLCBzZXAgPSAiIikKICAgIyBTZXQgdGhlIHNlZWQKICBzZXQuc2VlZCgxKQogICMgSm9pbnQgbW9kZWwKICBhc3NpZ24oSm9pbnRNX3ByZWZpeCwgU3VwZXJMZWFybmVyKFkgPSBnZXQoVHJhaW5feV9wcmVmaXgpLCBYID0gZ2V0KFRyYWluX3hfcHJlZml4KSwgZmFtaWx5ID0gZ2F1c3NpYW4oKSwgU0wubGlicmFyeSA9IG1vZGVscywgY3ZDb250cm9sID0gY29udHJvbCkpCiAgCiAgIyBBZGQgbGFzdCBlbGVtZW50IHRvIG1vZGVsc191c2UKICBtb2RlbHNfdXNlIDwtIGMobW9kZWxzX3VzZSwgSm9pbnRNX3ByZWZpeCkKICAKICAjIFVOVElMIEhFUkUgQUxMIEZJTkUgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAKICAjIFBSRURJQ1RJT05TIFRJTUUgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogIAogICMgSW5pdGlhbGl6ZSB0aGUgaW5uZXIgbGlzdCBmb3IgbW9kZWxzIGZvciB0aGUgY3VycmVudCBwZXJpb2QKICBNQUVfcGVyaW9kIDwtIGxpc3QoKQogIE1TRV9wZXJpb2QgPC0gbGlzdCgpCiAgUjJfcGVyaW9kIDwtIGxpc3QoKQogIEFUVF9wZXJpb2QgPC0gbGlzdCgpCgogIGZvciAobW9kZWwgaW4gbW9kZWxzX3VzZSkgewogICAgCiAgICAjIEV4dHJhY3RpbmcgdGhlIGFjdHVhbCBvYmplY3QgKGZvciBib3RoIFBSRS0gYW5kIFBPU1QtIHRyZWF0bWVudCBwcmVkaWN0aW9ucykKICAgIG1vZGVsX29iaiA8LSBnZXQobW9kZWwpCiAgICAKICAgICMgUFJFLVRSRUFUTUVOVCBQUkVESUNUSU9OUy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogIAogICAgIyBDcmVhdGUgdmFyaWFibGUgbmFtZXMgYmFzZWQgb24gdGhlIGxvb3AgaW5kZXgKICAgIGluX3ByZWRzX21vZGVsX3ByZV9wcmVmaXggPC0gcGFzdGUoImluX3ByZWRzXyIsIG1vZGVsLCAiX3ByZSIsIHNlcCA9ICIiKQogICAgY3ZfcHJlZHNfbW9kZWxfcHJlX3ByZWZpeCA8LSBwYXN0ZSgiaW5fcHJlZHNfIiwgbW9kZWwsICJfcHJlIiwgc2VwID0gIiIpCiAgICBkYXRhX21vZGVsX3ByZV9wcmVmaXggPC0gcGFzdGUoImRhdGFfIiwgbW9kZWwsICJfcHJlIiwgc2VwID0gIiIpCiAgCiAgICAjIEFzc2lnbiB0aGUgdmFsdWVzCiAgICBhc3NpZ24oaW5fcHJlZHNfbW9kZWxfcHJlX3ByZWZpeCwgYXMuZGF0YS5mcmFtZShtb2RlbF9vYmokbGlicmFyeS5wcmVkaWN0KSkKICAgIGFzc2lnbihjdl9wcmVkc19tb2RlbF9wcmVfcHJlZml4LCBhcy5kYXRhLmZyYW1lKG1vZGVsX29iaiRaKSkKICAKICAgICMgQ2hhbmdlIHRoZSBjb2x1bW5zIG5hbWVzCiAgICBvcmlnaW5hbF9pbl9wcmVkc19tb2RlbCA8LSBnZXQoaW5fcHJlZHNfbW9kZWxfcHJlX3ByZWZpeCkKICAgIGNvbG5hbWVzKG9yaWdpbmFsX2luX3ByZWRzX21vZGVsKSA8LSBzcHJpbnRmKCclc19pbl8lcycsIG1vZGVsLCBjb2xuYW1lcyhvcmlnaW5hbF9pbl9wcmVkc19tb2RlbCkpCiAgICBhc3NpZ24oaW5fcHJlZHNfbW9kZWxfcHJlX3ByZWZpeCwgb3JpZ2luYWxfaW5fcHJlZHNfbW9kZWwpCgogICAgb3JpZ2luYWxfY3ZfcHJlZHNfbW9kZWwgPC0gZ2V0KGN2X3ByZWRzX21vZGVsX3ByZV9wcmVmaXgpCiAgICBjb2xuYW1lcyhvcmlnaW5hbF9jdl9wcmVkc19tb2RlbCkgPC0gc3ByaW50ZignJXNfY3ZfJXMnLCBtb2RlbCwgY29sbmFtZXMob3JpZ2luYWxfY3ZfcHJlZHNfbW9kZWwpKQogICAgYXNzaWduKGN2X3ByZWRzX21vZGVsX3ByZV9wcmVmaXgsIG9yaWdpbmFsX2N2X3ByZWRzX21vZGVsKQogIAogICAgIyBKb2luaW5nIGJvdGggdmFyaWFibGVzIGludG8gYSBkYXRhZnJhbWUKICAgIGFzc2lnbihkYXRhX21vZGVsX3ByZV9wcmVmaXgsIGNiaW5kKGdldChpbl9wcmVkc19tb2RlbF9wcmVfcHJlZml4KSwgZ2V0KGN2X3ByZWRzX21vZGVsX3ByZV9wcmVmaXgpKSkKICAgIAogICAgCiAgICAjIExFVCdTIFJFQ09WRVIgVEhFIENST1NTVkFMSURBVEVEIEVSUk9SUy0tLS0tCiAgICAKICAgICMgQ3JlYXRlIHZhcmlhYmxlIG5hbWVzIGJhc2VkIG9uIHRoZSBsb29wIGluZGV4CiAgICBDVl9uYW1lcyA8LSBwYXN0ZSgiQ1ZfRV8iLCBtb2RlbCwgc2VwID0gIiIpCiAgICAKICAgICMgQXNzaWduIHRoZSB2YWx1ZXMgCiAgICBhc3NpZ24oQ1ZfbmFtZXMsIGdldChUcmFpbl95X3ByZWZpeCkgLSBnZXQoY3ZfcHJlZHNfbW9kZWxfcHJlX3ByZWZpeCkpCiAgICAKICAgICMgUE9TVC1UUkVBVE1FTlQgUFJFRElDVElPTlMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgICAKICAgICMgQ3JlYXRlIHZhcmlhYmxlIG5hbWVzIGJhc2VkIG9uIHRoZSBsb29wIGluZGV4CiAgICBwcmVkc19tb2RlbF9wb3N0X3ByZWZpeCA8LSBwYXN0ZSgicHJlZE1vZGVsXyIsIG1vZGVsLCAiX3Bvc3QiLCBzZXAgPSAiIikKICAgIGRhdGFfbW9kZWxfcG9zdF9wcmVmaXggPC0gcGFzdGUoImRhdGFfIiwgbW9kZWwsICJfcG9zdCIsIHNlcCA9ICIiKQogICAgCiAgICAjIEFzc2lnbiB0aGUgdmFsdWVzCiAgICBhc3NpZ24ocHJlZHNfbW9kZWxfcG9zdF9wcmVmaXgsIHByZWRpY3QobW9kZWxfb2JqLCBEYXRhX2NvbXBsZXRlWF9hY3R1YWwsIG9ubHlTTCA9IFQpKQogICAgCiAgICAjIE5vdyBnZXQgdGhlIHByZWRzX21vZGVsX3Bvc3RfcHJlZml4IGFjdHVhbCB2YWx1ZQogICAgcHJlZHNfbW9kZWxfb2JqIDwtIGdldChwcmVkc19tb2RlbF9wb3N0X3ByZWZpeCkgIyBBbHNvIG5lZWRlZCBmb3IgdGhlIHN1YnNlcXVlbnQgc3RlcHMKICAgIAogICAgIyBBc3NpZ24gdGhlIHZhbHVlcyBub3cKICAgIGFzc2lnbihkYXRhX21vZGVsX3Bvc3RfcHJlZml4LCBhcy5kYXRhLmZyYW1lKHByZWRzX21vZGVsX29iaiRwcmVkKSkKICAgIAogICAgIyBDaGFuZ2UgdGhlIGNvbHVtbnMgbmFtZXMKICAgIG9yaWdpbmFsX2RhdGFfbW9kZWxfcG9zdCA8LSBnZXQoZGF0YV9tb2RlbF9wb3N0X3ByZWZpeCkKICAgIGNvbG5hbWVzKG9yaWdpbmFsX2RhdGFfbW9kZWxfcG9zdCkgPC0gc3ByaW50ZignJXNfaW5fJXMnLCBtb2RlbCwgY29sbmFtZXMob3JpZ2luYWxfZGF0YV9tb2RlbF9wb3N0KSkKICAgIGFzc2lnbihkYXRhX21vZGVsX3Bvc3RfcHJlZml4LCBvcmlnaW5hbF9kYXRhX21vZGVsX3Bvc3QpCiAgICAKICAgICMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAgIAogICAgIyBMRVQnUyBHRVQgVEhFIERFTlNJVElFUyBGT1IgUExPVFRJTkctLS0tLS0KICAgIAogICAgIyBDcmVhdGUgdmFyaWFibGUgbmFtZXMgYmFzZWQgb24gdGhlIGxvb3AgaW5kZXgKICAgIERlbnNpdHlfbmFtZSA8LSBwYXN0ZSgiZGVuc2l0eV8iLCBtb2RlbCwgc2VwID0gIiIpCiAgICAKICAgICMgQXNzaWduIHRoZSB2YWx1ZXMKICAgICMgYXNzaWduKERlbnNpdHlfbmFtZSwgZGF0YV9tb2RlbF9wb3N0X3ByZWZpeFssIDFdKSAjIFRoaXMgd2lsbCByZXR1cm4gdGhlIHZhbHVlIGFzIGEgdmVjdG9yCiAgICBhc3NpZ24oRGVuc2l0eV9uYW1lLCBkZW5zaXR5KHByZWRzX21vZGVsX29iaiRwcmVkWywgMV0pKSAjIFRoaXMgd2lsbCByZXR1cm4gdGhlIHZhbHVlIGFzIGEgdmVjdG9yLCB1c2luZyBwcmVkc19tb2RlbF9vYmogT0JKRUNUCiAgICAKICAgICMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAgIAogICAgIyBMRVQnUyBHRVQgVEhFIE1BRSwgTVNFICYgUjIKICAgIAogICAgIyBXZSB3aWxsIHVzZSwgTUFFIChtZWFuIGFic29sdXRlIGVycm9yKSwgTVNFIChtZWFuIHNxdWFyZWQgZXJyb3IsIHRoaXMgb25lIG1ha2VzIHN1cmUgdG8gZGVhbCB3aXRoIG5lZ2F0aXZlIGRpc3RhbmNlcyksIFIyIChSLXNxdWFyZWQpCgogICAgIyBDb21wdXRlIE1BRSwgTVNFICYgUjIgZm9yIHRoZSBjdXJyZW50IG1vZGVsIGFuZCBwZXJpb2QKICAgIE1BRV92YWx1ZSA8LSBtYWUoRGF0YV9jb21wbGV0ZVlfYWN0dWFsLCBhcy52ZWN0b3IodW5saXN0KGdldChkYXRhX21vZGVsX3Bvc3RfcHJlZml4KSkpKQogICAgTVNFX3ZhbHVlIDwtIG1zZShEYXRhX2NvbXBsZXRlWV9hY3R1YWwsIGFzLnZlY3Rvcih1bmxpc3QoZ2V0KGRhdGFfbW9kZWxfcG9zdF9wcmVmaXgpKSkpCiAgICBSMl92YWx1ZSA8LSBSMihEYXRhX2NvbXBsZXRlWV9hY3R1YWwsIGFzLnZlY3Rvcih1bmxpc3QoZ2V0KGRhdGFfbW9kZWxfcG9zdF9wcmVmaXgpKSkpCgogICAgIyBTdG9yZSB0aGUgTUFFLCBNU0UsIFIyIHZhbHVlIGluIHRoZSByZXNwZWN0aXZlIGxpc3QgYmFzZWQgb24gdGhlIG1vZGVsIHR5cGUgVEhTIEZPUiBFQUNICiAgICAKICAgICMgU3RvcmUgdGhlIE1BRSB2YWx1ZSBpbiB0aGUgaW5uZXIgbGlzdCBmb3IgdGhlIGN1cnJlbnQgbW9kZWwKICAgIE1BRV9wZXJpb2RbW21vZGVsXV0gPC0gTUFFX3ZhbHVlCiAgICAKICAgICMgU3RvcmUgdGhlIE1BRSB2YWx1ZSBpbiB0aGUgaW5uZXIgbGlzdCBmb3IgdGhlIGN1cnJlbnQgbW9kZWwKICAgIE1TRV9wZXJpb2RbW21vZGVsXV0gPC0gTVNFX3ZhbHVlCiAgICAKICAgICMgU3RvcmUgdGhlIE1BRSB2YWx1ZSBpbiB0aGUgaW5uZXIgbGlzdCBmb3IgdGhlIGN1cnJlbnQgbW9kZWwKICAgIFIyX3BlcmlvZFtbbW9kZWxdXSA8LSBSMl92YWx1ZQoKICAgICMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAgIAogICAgIyBMRVQnUyBHRVQgVEhFIERJRkZFUkVOQ0VTIFRIQVQgV0UgV0lMTCBORUVEIFRPIFJFQ09WRVIgVEhFIEFUVAogICAgCiAgICAjIENyZWF0ZSB2YXJpYWJsZSBuYW1lcyBiYXNlZCBvbiB0aGUgbG9vcCBpbmRleAogICAgRGlmZmVyZW5jZXMgPC0gcGFzdGUoIkRpZmZlcmVuY2VfIiwgbW9kZWwsIHNlcCA9ICIiKQogICAgCiAgICAjIEFzc2lnbiB0aGUgdmFsdWVzIG5vdwogICAgI2Fzc2lnbihEaWZmZXJlbmNlcywgYXMudmVjdG9yKHVubGlzdChnZXQoZGF0YV9tb2RlbF9wb3N0X3ByZWZpeCkpKSAtIERhdGFfY29tcGxldGVZX2FjdHVhbCkKICAgIGFzc2lnbihEaWZmZXJlbmNlcywgYXMudmVjdG9yKHVubGlzdChEYXRhX2NvbXBsZXRlWV9hY3R1YWwgLSBnZXQoZGF0YV9tb2RlbF9wb3N0X3ByZWZpeCkpKSkKICAgIAogICAgIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogICAgCiAgICAjIExFVCdTIEdFVCBBVFQgUEVSIFBFUklPRCBQRVIgTU9ERUwKICAgIAogICAgIyBDcmVhdGUgdmFyaWFibGUgbmFtZXMgYmFzZWQgb24gdGhlIGxvb3AgaW5kZXgKICAgICMgQVRUIDwtIHBhc3RlKCJBVFRfIiwgbW9kZWwsIHNlcCA9ICIiKSAjIEFDVFVBTExZIE5PIE5FRUQKICAgIAogICAgIyBDb21wdXRlIEFUVCBmb3IgdGhlIGN1cnJlbnQgbW9kZWwgYW5kIHBlcmlvZAogICAgQVRUX3ZhbHVlIDwtIG1lYW4oZ2V0KHBhc3RlKCJEaWZmZXJlbmNlXyIsIG1vZGVsLCBzZXAgPSAiIikpKQogICAgCiAgICAjIFN0b3JlIHRoZSBNQUUgdmFsdWUgaW4gdGhlIGlubmVyIGxpc3QgZm9yIHRoZSBjdXJyZW50IG1vZGVsCiAgICBBVFRfcGVyaW9kW1ttb2RlbF1dIDwtIEFUVF92YWx1ZQogICAgCiAgfQogIAogICMgTUFFLCBNU0UsIFIyICYgQVRUIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAjIEFwcGVuZCB0aGUgaW5uZXIgbGlzdCB0byB0aGUgb3V0ZXIgbGlzdCBmb3IgdGhlIGN1cnJlbnQgcGVyaW9kCiAgTUFFW1twYXN0ZSgiUGVyaW9kIiwgaSwgc2VwID0gIl8iKV1dIDwtIE1BRV9wZXJpb2QKICBNU0VbW3Bhc3RlKCJQZXJpb2QiLCBpLCBzZXAgPSAiXyIpXV0gPC0gTVNFX3BlcmlvZAogIFIyW1twYXN0ZSgiUGVyaW9kIiwgaSwgc2VwID0gIl8iKV1dIDwtIFIyX3BlcmlvZAogIEFUVFtbcGFzdGUoIlBlcmlvZCIsIGksIHNlcCA9ICJfIildXSA8LSBBVFRfcGVyaW9kCiAgCiAgIyBEZW5zaXRpZXMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAKICAjIENyZWF0ZSB2YXJpYWJsZSBuYW1lcyBiYXNlZCBvbiB0aGUgbG9vcCBpbmRleAogIERhdGFfcGxvdHRpbmcgPC0gcGFzdGUoIlRvUGxvdERhdGFfZGVuc2l0aWVzX3QiLCBpLCBzZXAgPSAiIikKCiAgIyBHZXQgdGhlIHZhbHVlcyBvZiB0aGUgbW9kZWxzIGFnYWluIC0gVXNpbmcgdGhlIGZhY3QgdGhhdCB3ZSBoYXZlIGFscmVhZHkgZGVmaW5lZCBvdXIgbW9kZWxzIGFib3ZlIGluICJtb2RlbHNfdXNlIiBvdXRzaWRlIHRoZSBtb2RlbCBsb29wCiAgWV9hY3R1YWxfZGVuc2l0eSA8LSBnZXQocGFzdGUoIkRlbnNpdHlfIiwgRGF0YV9jb21wbGV0ZVlfcHJlZml4LCBzZXAgPSAiIikpCiAgCiAgIyBQZXJpb2QgZGVuc2l0aWVzCiAgcGVyaW9kX2RlbnNpdGllcyA8LSBsaXN0KCkKICAKICBmb3IgKG0gaW4gc2VxX2Fsb25nKG1vZGVsc191c2UpKSB7CiAgICAKICAgICMgRGVmaW5pbmcgdGhlIG5hbWVzIG9mIHRoZSBkZW5zaXRpZXMKICAgIG1vZGVsX25hbWUgPC0gbW9kZWxzX25hbWVzX2FjdFttXSAjIFRvIGRlZmluZSB0aGUgbmFtZSBvZiB0aGUgbW9kZWwKICAgIHByZWZpeF9kZW5zaXR5IDwtIHBhc3RlKG1vZGVsX25hbWUsICJkZW5zaXR5Iiwgc2VwID0gIl8iKQogICAgCiAgICAjIERlZmluaW5nIHRoZSB2YWx1ZXMgdG8gYmUgYXNzaWduZWQKICAgIG1vZGVsX3ZhbHVlcyA8LSBnZXQocGFzdGUoImRlbnNpdHlfIiwgbW9kZWxzX3VzZVttXSwgc2VwID0gIiIpKQoKICAgICMgQ3JlYXRlIHZhcmlhYmxlIG5hbWVzIGR5bmFtaWNhbGx5CiAgICBhc3NpZ24ocHJlZml4X2RlbnNpdHksIG1vZGVsX3ZhbHVlcykKICAgIAogICAgIyBTdG9yZSB0aGUgZGVuc2l0aWVzCiAgICBwZXJpb2RfZGVuc2l0aWVzW1twcmVmaXhfZGVuc2l0eV1dIDwtIGdldChwcmVmaXhfZGVuc2l0eSkKICAgIAogIH0KCiAgIyBMaXN0IG9mIG1vZGVscwogIGxpc3RfbW9kZWxzIDwtIGMoIllfYWN0dWFsIiwgIkxBU1NPIiwgIlJhbmRvbSBGb3Jlc3QiLCAiWEdCb29zdCIsICJKb2ludE0iKQogIAogICMgU3RvcmUgbXkgZGVuc2l0aWVzCiAgCiAgIyBEZWZpbmluZyB2YXJpYWJsZSBuYW1lcyBpbnNpZGUgdGhlIGxpc3QKICBuYW1lc19kZW5zaXRpZXNfcGVyaW9kcyA8LSBwYXN0ZSgidCIsIGksIHNlcCA9ICIiKQogIGRlbnNpdGllc19saXN0W1tuYW1lc19kZW5zaXRpZXNfcGVyaW9kc11dIDwtIHBlcmlvZF9kZW5zaXRpZXMKICAKICAjIEFkZGluZyB0aGUgdmFsdWUgb2YgWSBkZW5zaXR5LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgZGVuc2l0aWVzX3lbW3Bhc3RlKCJEZW5zaXR5X3l0IiwgaSwgc2VwID0gIiIpXV0gPC0gWV9hY3R1YWxfZGVuc2l0eQoKfQoKIyBTdGF0aXN0aWNzIAoKIyBDb21iaW5lIHRoZSB2ZWN0b3JzIGludG8gYSBsaXN0ClN0YXRpdGljcyA8LSBsaXN0KAogIEFUVCA9IEFUVCwKICBNQUUgPSBNQUUsCiAgTVNFID0gTVNFLAogIFIyID0gUjIKKQoKIyBBVkVSQUdFUy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyBOb3cgZGVwZW5kaW5nIG9uIHRoZSBudW1iZXIgb2YgcGVyaW9kcyBhbmQgdGhlIG51bWJlciBvZiBtb2RlbHMgc28gd2UgbmVlZCB0byBkaXZpZGUgZm9yIGV4YW1wZWwgaWYgbW9kZWxzIGFyZQpudW1fcGVyaW9kcyA9IChlbmRpbmdfdGVzdF9wZXJpb2QgLSBzdGFydGluZ190ZXN0X3BlcmlvZCkgKyAxCm51bV9tb2RlbHMgPSBsZW5ndGgobW9kZWxzX25hbWVzX2FjdCkKCiMgQXZlcmFnZXMgcGVyIG1vZGVsClN0YXRpc3RpY19hdmVyYWdlcyA8LSBsaXN0KCkKCiMgU3RhdGlzdGljcyBsaXN0ClN0YXRpc3RpY3NfbGlzdCA8LSBjKCJBVFQiLCAiTUFFIiwgIk1TRSIsICJSMiIpCgojIExvb3Agb3ZlciBTdGF0aXN0aWNzIGxpc3QKZm9yIChzIGluIFN0YXRpc3RpY3NfbGlzdCkgewogIAogICMgTGlzdCBhdmVyYWdlcwogIEF2ZXJhZ2VzX2xpc3QgPC0gbGlzdCgpCiAgCiAgIyBMb29wIG92ZXIgbW9kZWxzCiAgZm9yIChtb2QgaW4gbW9kZWxzX25hbWVzX2FjdCkgewogIAogICAgIyBDcmVhdGUgdGhlIG5hbWUgb2YgdGhlIHZhcmlhYmxlCiAgICBQcmVmaXhfYXZlcmFnZSA8LSBwYXN0ZShzLCBtb2QsICJhdmVyYWdlIiwgc2VwID0gIl8iKQoKICAgICMgSW5pdGlhbGl6ZSBtZWFuX3Blcl9tb2RlbCBmb3IgZWFjaCBtb2RlbAogICAgbWVhbl9wZXJfbW9kZWwgPC0gMAoKICAgICMgTG9vcCBvdmVyIHBlcmlvZHMKICAgIGZvciAoaSBpbiAxOm51bV9wZXJpb2RzKSB7CiAgICAgICMgQ29sbGVjdGluZyB0aGUgbWVhbiBmb3IgZWFjaCBtb2RlbCBmb3IgZWFjaCBwZXJpb2QKICAgICAgc3RhdF92YWx1ZSA8LSBnZXQocGFzdGUocywgc2VwID0gIiIpKVtbaV1dW1t3aGljaChtb2RlbHNfbmFtZXNfYWN0ID09IG1vZCldXQogICAgICBtZWFuX3Blcl9tb2RlbCA8LSBtZWFuX3Blcl9tb2RlbCArIHN0YXRfdmFsdWUKICAgIH0KCiAgICAjIENhbGN1bGF0ZSB0aGUgYXZlcmFnZSBhY3Jvc3MgYWxsIHBlcmlvZHMgZm9yIHRoZSBjdXJyZW50IG1vZGVsCiAgICBtZWFuX3Blcl9tb2RlbCA8LSBtZWFuX3Blcl9tb2RlbCAvIG51bV9wZXJpb2RzCgogICAgIyBTdG9yZSB0aGUgcmVzdWx0IGluIEF2ZXJhZ2VzX2xpc3QKICAgIEF2ZXJhZ2VzX2xpc3RbW1ByZWZpeF9hdmVyYWdlXV0gPC0gbWVhbl9wZXJfbW9kZWwKICB9CiAgCiAgIyBTdG9yZSB0aGUgdmFsdWVzCiAgU3RhdGlzdGljX2F2ZXJhZ2VzW1tzXV0gPC0gQXZlcmFnZXNfbGlzdAp9CgoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMgQUNUVUFMIE9VVFBVVFMgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKb3V0cHV0IDwtIGxpc3QoCiAgRml0bmVzc1N0YXRpc3RpY3MgPSBTdGF0aXRpY3MsCiAgYXZlcmFnZV92YWx1ZXMgPSBTdGF0aXN0aWNfYXZlcmFnZXMsCiAgZGVuc2l0aWVzX3kgPSBkZW5zaXRpZXNfeSwKICBkZW5zaXRpZXNfTUxfbGlzdCA9IGRlbnNpdGllc19saXN0CikKCnJldHVybihvdXRwdXQpCgp9CgpgYGAKCgojIEFEVkFOQ0VEIEZVTkNUSU9OIFRPIFJFQ09WRVIgVEhFIEFUVCwgTUFFLCBNU0UsIFIyIEFORCBUSEUgREVOU0lUSUVTIC0gRFJERAoKYGBge3J9CkRSRERfUkVTVUxUUyA8LSBmdW5jdGlvbihNeURhdGEsIHN0YXJ0aW5nX3Rlc3RfcGVyaW9kLCBlbmRpbmdfdGVzdF9wZXJpb2QpewogIAojIElOUFVUUwojIE15RGF0YSA9IE15RGF0YQojIHN0YXJ0aW5nX3Rlc3RfcGVyaW9kID0gMwojIGVuZGluZ190ZXN0X3BlcmlvZCA9IDUKCiMgVGhpcyB2ZWN0b3Igd2lsbCBzdG9yZSBteSBkaWZmZXJlbnQgcmVncmVzc2lvbiB2YWx1ZXMKRFJERF9saXN0IDwtIGxpc3QoKQogIAogIGZvciAoaSBpbiBzdGFydGluZ190ZXN0X3BlcmlvZDplbmRpbmdfdGVzdF9wZXJpb2QpIHsKICAgIAogICAgIyBTdWJzZXQgTXlEYXRhIGJhc2VkIG9uIHRoZSBjb25kaXRpb24gZC5kX3RfaS0xID09IDAsIGp1c3QgZm9yIHRoZSBwZW9wbGUgdGhhdCBpbiB0aGUgcHJldmlvdXMgcGVyaW9kIHdlcmUgbm90IHRyZWF0ZWQKICAgIE15RGF0YSA8LSBNeURhdGFbTXlEYXRhW1twYXN0ZSgiZC5kX3QiLCBpLTEsIHNlcCA9ICIiKV1dID09IDAsIF0KICAgIAogICAgIyBERFJEIHZhbHVlcwogICAgRERSRF92YWx1ZSA8LSBkcmRpZF9pbXBfcGFuZWwoeTEgPSBNeURhdGFbW3Bhc3RlKCJ5IiwgaSAsIHNlcCA9ICIuIildXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5MCA9IE15RGF0YVtbcGFzdGUoInkiLCBpLTEgLCBzZXAgPSAiLiIpXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEID0gTXlEYXRhW1twYXN0ZSgiZC5kX3QiLCBpICwgc2VwID0gIiIpXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3ZhcmlhdGVzID0gY2JpbmQoTXlEYXRhW1twYXN0ZSgieC54X3QiLCBpLCAiLjEiLCBzZXAgPSAiIildXSwgTXlEYXRhW1twYXN0ZSgieC54X3QiLCBpLCAiLjIiLCBzZXAgPSAiIildXSwgTXlEYXRhW1twYXN0ZSgieC54X3QiLCBpLCAiLjMiLCBzZXAgPSAiIildXSwgTXlEYXRhW1twYXN0ZSgieC54X3QiLCBpLCAiLjQiLCBzZXAgPSAiIildXSwgTXlEYXRhW1twYXN0ZSgieC54X3QiLCBpLCAiLjUiLCBzZXAgPSAiIildXSkpCgogICAgIyBBZGQgdGhlbSB0byB0aGUgbGlzdAogICAgRFJERF9saXN0W1twYXN0ZSgiRFJERF90IiwgaSwgc2VwID0gIiIpXV0gPC0gRERSRF92YWx1ZQogIH0KCgojIFJlc3VsdCBteSBsaXN0CnJldHVybihEUkREX2xpc3QpICAKCn0KYGBgCgoKIyMjIyBOT1cgTEVUJ1MgU0hPVyBPVVIgUkVTVUxUUyAjIyMjCgojIElOUFVUUwpgYGB7cn0KTXlEYXRhID0gTXlEYXRhICMgb3Igd2hpY2hldmVyIGRhdGEgeW91IGhhdmUKQ1ZfbnVtX2ZvbGRzID0gMTAgIyBvciB3aGF0ZXZlciBtYXkgYmUgZGVjaWRlZApzdGFydGluZ190ZXN0X3BlcmlvZCA9IDMgIyBjYW4gYmUgYWRhcHRlZCBkZXBlbmRpbmcgb24gdGhlIHN0YXJ0aW5nIHRyZWF0bWVudCBwZXJpb2Qgb2YgeW91ciBkYXRhYmFzZQplbmRpbmdfdGVzdF9wZXJpb2QgPSA1ICMgY2FuIGJlIGFkYXB0ZWQgZGVwZW5kaW5nIG9uIHRoZSBlbmRpbmcgdHJlYXRtZW50IHBlcmlvZCBvZiB5b3VyIGRhdGFiYXNlCm1vZGVscyA8LSBjKCJTTC5nbG1uZXQiLCAiU0wucmFuZG9tRm9yZXN0IiwgIlNMLnhnYm9vc3QiLCAiU0wua2VybmVsS25uIikgIyBjYW4gYmUgYWRhcHRlZCBnaXZlbiB0aGUgbW9kZWxzIHRoYXQgeW91IHdpbGwgYmUgdXNpbmcKbW9kZWxzX25hbWVzIDwtIGMoIkxBU1NPIiwgIlJGIiwgIlhnQiIsICJLZXJuZWxLbm4iKSAjIGNhbiBiZSBhZGFwdGVkIGdpdmVuIHRoZSBtb2RlbHMgdGhhdCB5b3Ugd2lsbCBiZSB1c2luZwpgYGAKCgoKIyAxKSBNQUNISU5FIExFQVJOSU5HCgpSZXN1bHRzIG9mIHRoZSBmdW5jdGlvbgpgYGB7cn0KTUxfUkVTVUxUU19TRVZFUkFMIDwtIEFUVF9NTF9nZW5lcmF0b3JfQURWQU5DRUQoTXlEYXRhLCBDVl9udW1fZm9sZHMsIHN0YXJ0aW5nX3Rlc3RfcGVyaW9kLCBlbmRpbmdfdGVzdF9wZXJpb2QsIG1vZGVscywgbW9kZWxzX25hbWVzKQpgYGAKCgoKIyBHUkFQSFMgQU5EIE1BSU4gUkVTVUxUUyBPRiBUSEUgRlVOQ1RJT04KCkFUVApgYGB7cn0KIyBUcmFuc2Zvcm0gdGhlIEFUVCBsaXN0IGludG8gYSBkYXRhIGZyYW1lCkFUVF9kZiA8LSBkYXRhLmZyYW1lKG1hdHJpeCh1bmxpc3QoTUxfUkVTVUxUU19TRVZFUkFMJEZpdG5lc3NTdGF0aXN0aWNzJEFUVCksIG5yb3cgPSBsZW5ndGgoTUxfUkVTVUxUU19TRVZFUkFMJEZpdG5lc3NTdGF0aXN0aWNzJEFUVCksIGJ5cm93ID0gVFJVRSksIHJvdy5uYW1lcyA9IG5hbWVzKE1MX1JFU1VMVFNfU0VWRVJBTCRGaXRuZXNzU3RhdGlzdGljcyRBVFQpKQoKIyBXZSB3aWxsIGFsc28gdXNlIHRoZSBhdmVyYWdlcyBsaXN0cyBmb3Igb3VyIHB1cnBvc2VzCkFUVF9hdmVyYWdlcyA8LSBkYXRhLmZyYW1lKG1hdHJpeCh1bmxpc3QoTUxfUkVTVUxUU19TRVZFUkFMJGF2ZXJhZ2VfdmFsdWVzJEFUVCksIG5yb3cgPSBsZW5ndGgoTUxfUkVTVUxUU19TRVZFUkFMJGF2ZXJhZ2VfdmFsdWVzJEFUVCksIGJ5cm93ID0gVFJVRSksIHJvdy5uYW1lcyA9IG5hbWVzKE1MX1JFU1VMVFNfU0VWRVJBTCRhdmVyYWdlX3ZhbHVlcyRBVFQpKQoKIyBCaW5kIGJvdGggb2YgdGhlIGp1c3QgZGF0YWZyYW1lcwpBVFRfZm9yVGFibGUgPC0gY2JpbmQodChBVFRfZGYpLCBBVFRfYXZlcmFnZXMpCgojIEFkZCBjb2x1bW4gbmFtZXMKY29sbmFtZXMoQVRUX2ZvclRhYmxlKSA8LSBjKCJ0MyIsICJ0NCIsICJ0NSIsICJhdmVyYWdlIikgCgojIEFkZCByb3cgbmFtZXMKcm93bmFtZXMoQVRUX2ZvclRhYmxlKSA8LSBjKG1vZGVsc19uYW1lcywgIkpvaW50TSIpCgojIENyZWF0ZSBhIGNvZGUgZm9yIGEgTGFUZVggVGFibGUKbGF0ZXhfY29kZV9BVFQgPC0geHRhYmxlKEFUVF9mb3JUYWJsZSwgY2FwdGlvbiA9ICJNTCBBVFQgcGVyIG1vZGVsIHBlciBwZXJpb2QgZXN0aW1hdGVkIikKCiMgUHJpbnQgdGhlIExhVGVYIGNvZGUKcHJpbnQobGF0ZXhfY29kZV9BVFQsIGluY2x1ZGUucm93bmFtZXMgPSBUKQpgYGAKCk1BRQpgYGB7cn0KIyBUcmFuc2Zvcm0gdGhlIEFUVCBsaXN0IGludG8gYSBkYXRhIGZyYW1lCk1BRV9kZiA8LSBkYXRhLmZyYW1lKG1hdHJpeCh1bmxpc3QoTUxfUkVTVUxUU19TRVZFUkFMJEZpdG5lc3NTdGF0aXN0aWNzJE1BRSksIG5yb3cgPSBsZW5ndGgoTUxfUkVTVUxUU19TRVZFUkFMJEZpdG5lc3NTdGF0aXN0aWNzJE1BRSksIGJ5cm93ID0gVFJVRSksIHJvdy5uYW1lcyA9IG5hbWVzKE1MX1JFU1VMVFNfU0VWRVJBTCRGaXRuZXNzU3RhdGlzdGljcyRNQUUpKQoKIyBXZSB3aWxsIGFsc28gdXNlIHRoZSBhdmVyYWdlcyBsaXN0cyBmb3Igb3VyIHB1cnBvc2VzCk1BRV9hdmVyYWdlcyA8LSBkYXRhLmZyYW1lKG1hdHJpeCh1bmxpc3QoTUxfUkVTVUxUU19TRVZFUkFMJGF2ZXJhZ2VfdmFsdWVzJE1BRSksIG5yb3cgPSBsZW5ndGgoTUxfUkVTVUxUU19TRVZFUkFMJGF2ZXJhZ2VfdmFsdWVzJE1BRSksIGJ5cm93ID0gVFJVRSksIHJvdy5uYW1lcyA9IG5hbWVzKE1MX1JFU1VMVFNfU0VWRVJBTCRhdmVyYWdlX3ZhbHVlcyRNQUUpKQoKIyBCaW5kIGJvdGggb2YgdGhlIGp1c3QgZGF0YWZyYW1lcwpNQUVfZm9yVGFibGUgPC0gY2JpbmQodChNQUVfZGYpLCBNQUVfYXZlcmFnZXMpCgojIEFkZCBjb2x1bW4gbmFtZXMKY29sbmFtZXMoTUFFX2ZvclRhYmxlKSA8LSBjKCJ0MyIsICJ0NCIsICJ0NSIsICJhdmVyYWdlIikgCgojIEFkZCByb3cgbmFtZXMKcm93bmFtZXMoTUFFX2ZvclRhYmxlKSA8LSBjKG1vZGVsc19uYW1lcywgIkpvaW50TSIpCgojIENyZWF0ZSBhIGNvZGUgZm9yIGEgTGFUZVggVGFibGUKbGF0ZXhfY29kZV9NQUUgPC0geHRhYmxlKE1BRV9mb3JUYWJsZSwgY2FwdGlvbiA9ICJNTCBNQUUgcGVyIG1vZGVsIHBlciBwZXJpb2QgZXN0aW1hdGVkIikKCiMgUHJpbnQgdGhlIExhVGVYIGNvZGUKcHJpbnQobGF0ZXhfY29kZV9NQUUsIGluY2x1ZGUucm93bmFtZXMgPSBUKQpgYGAKCk1TRQpgYGB7cn0KIyBUcmFuc2Zvcm0gdGhlIEFUVCBsaXN0IGludG8gYSBkYXRhIGZyYW1lCk1TRV9kZiA8LSBkYXRhLmZyYW1lKG1hdHJpeCh1bmxpc3QoTUxfUkVTVUxUU19TRVZFUkFMJEZpdG5lc3NTdGF0aXN0aWNzJE1TRSksIG5yb3cgPSBsZW5ndGgoTUxfUkVTVUxUU19TRVZFUkFMJEZpdG5lc3NTdGF0aXN0aWNzJE1TRSksIGJ5cm93ID0gVFJVRSksIHJvdy5uYW1lcyA9IG5hbWVzKE1MX1JFU1VMVFNfU0VWRVJBTCRGaXRuZXNzU3RhdGlzdGljcyRNU0UpKQoKIyBXZSB3aWxsIGFsc28gdXNlIHRoZSBhdmVyYWdlcyBsaXN0cyBmb3Igb3VyIHB1cnBvc2VzCk1TRV9hdmVyYWdlcyA8LSBkYXRhLmZyYW1lKG1hdHJpeCh1bmxpc3QoTUxfUkVTVUxUU19TRVZFUkFMJGF2ZXJhZ2VfdmFsdWVzJE1TRSksIG5yb3cgPSBsZW5ndGgoTUxfUkVTVUxUU19TRVZFUkFMJGF2ZXJhZ2VfdmFsdWVzJE1TRSksIGJ5cm93ID0gVFJVRSksIHJvdy5uYW1lcyA9IG5hbWVzKE1MX1JFU1VMVFNfU0VWRVJBTCRhdmVyYWdlX3ZhbHVlcyRNU0UpKQoKIyBCaW5kIGJvdGggb2YgdGhlIGp1c3QgZGF0YWZyYW1lcwpNU0VfZm9yVGFibGUgPC0gY2JpbmQodChNU0VfZGYpLCBNU0VfYXZlcmFnZXMpCgojIEFkZCBjb2x1bW4gbmFtZXMKY29sbmFtZXMoTVNFX2ZvclRhYmxlKSA8LSBjKCJ0MyIsICJ0NCIsICJ0NSIsICJhdmVyYWdlIikgCgojIEFkZCByb3cgbmFtZXMKcm93bmFtZXMoTVNFX2ZvclRhYmxlKSA8LSBjKG1vZGVsc19uYW1lcywgIkpvaW50TSIpCgojIENyZWF0ZSBhIGNvZGUgZm9yIGEgTGFUZVggVGFibGUKbGF0ZXhfY29kZV9NU0UgPC0geHRhYmxlKE1TRV9mb3JUYWJsZSwgY2FwdGlvbiA9ICJNTCBNU0UgcGVyIG1vZGVsIHBlciBwZXJpb2QgZXN0aW1hdGVkIikKCiMgUHJpbnQgdGhlIExhVGVYIGNvZGUKcHJpbnQobGF0ZXhfY29kZV9NU0UsIGluY2x1ZGUucm93bmFtZXMgPSBUKQpgYGAKClIyCmBgYHtyfQojIFRyYW5zZm9ybSB0aGUgQVRUIGxpc3QgaW50byBhIGRhdGEgZnJhbWUKUjJfZGYgPC0gZGF0YS5mcmFtZShtYXRyaXgodW5saXN0KE1MX1JFU1VMVFNfU0VWRVJBTCRGaXRuZXNzU3RhdGlzdGljcyRSMiksIG5yb3cgPSBsZW5ndGgoTUxfUkVTVUxUU19TRVZFUkFMJEZpdG5lc3NTdGF0aXN0aWNzJFIyKSwgYnlyb3cgPSBUUlVFKSwgcm93Lm5hbWVzID0gbmFtZXMoTUxfUkVTVUxUU19TRVZFUkFMJEZpdG5lc3NTdGF0aXN0aWNzJFIyKSkKCiMgV2Ugd2lsbCBhbHNvIHVzZSB0aGUgYXZlcmFnZXMgbGlzdHMgZm9yIG91ciBwdXJwb3NlcwpSMl9hdmVyYWdlcyA8LSBkYXRhLmZyYW1lKG1hdHJpeCh1bmxpc3QoTUxfUkVTVUxUU19TRVZFUkFMJGF2ZXJhZ2VfdmFsdWVzJFIyKSwgbnJvdyA9IGxlbmd0aChNTF9SRVNVTFRTX1NFVkVSQUwkYXZlcmFnZV92YWx1ZXMkUjIpLCBieXJvdyA9IFRSVUUpLCByb3cubmFtZXMgPSBuYW1lcyhNTF9SRVNVTFRTX1NFVkVSQUwkYXZlcmFnZV92YWx1ZXMkUjIpKQoKIyBCaW5kIGJvdGggb2YgdGhlIGp1c3QgZGF0YWZyYW1lcwpSMl9mb3JUYWJsZSA8LSBjYmluZCh0KFIyX2RmKSwgUjJfYXZlcmFnZXMpCgojIEFkZCBjb2x1bW4gbmFtZXMKY29sbmFtZXMoUjJfZm9yVGFibGUpIDwtIGMoInQzIiwgInQ0IiwgInQ1IiwgImF2ZXJhZ2UiKSAKCiMgQWRkIHJvdyBuYW1lcwpyb3duYW1lcyhSMl9mb3JUYWJsZSkgPC0gYyhtb2RlbHNfbmFtZXMsICJKb2ludE0iKQoKIyBDcmVhdGUgYSBjb2RlIGZvciBhIExhVGVYIFRhYmxlCmxhdGV4X2NvZGVfUjIgPC0geHRhYmxlKFIyX2ZvclRhYmxlLCBjYXB0aW9uID0gIk1MIFIyIHBlciBtb2RlbCBwZXIgcGVyaW9kIGVzdGltYXRlZCIpCgojIFByaW50IHRoZSBMYVRlWCBjb2RlCnByaW50KGxhdGV4X2NvZGVfUjIsIGluY2x1ZGUucm93bmFtZXMgPSBUKQpgYGAKCkRlbnNpdGllcwoKYGBge3J9Cmxpc3RfbW9kZWxzIDwtIGMoIllfYWN0dWFsIiwgbW9kZWxzX25hbWVzLCAiSm9pbnRNIikKYGBgCgoKM3JkIHBlcmlvZApgYGB7cn0KIyBWYWx1ZXMgb2YgdGhlIGRlbnNpdGllcwpUb1Bsb3REYXRhX2RlbnNpdGllc190MyA8LSBkYXRhLmZyYW1lKAogIHZhbHVlID0gYyhNTF9SRVNVTFRTX1NFVkVSQUwkZGVuc2l0aWVzX3kkRGVuc2l0eV95dDMkeCwgCiAgICAgICAgICAgIE1MX1JFU1VMVFNfU0VWRVJBTCRkZW5zaXRpZXNfTUxfbGlzdCR0MyRMQVNTT19kZW5zaXR5JHgsIAogICAgICAgICAgICBNTF9SRVNVTFRTX1NFVkVSQUwkZGVuc2l0aWVzX01MX2xpc3QkdDMkUkZfZGVuc2l0eSR4LCAKICAgICAgICAgICAgTUxfUkVTVUxUU19TRVZFUkFMJGRlbnNpdGllc19NTF9saXN0JHQzJFhnQl9kZW5zaXR5JHgsCiAgICAgICAgICAgIE1MX1JFU1VMVFNfU0VWRVJBTCRkZW5zaXRpZXNfTUxfbGlzdCR0MyRLZXJuZWxLbm5fZGVuc2l0eSR4LAogICAgICAgICAgICBNTF9SRVNVTFRTX1NFVkVSQUwkZGVuc2l0aWVzX01MX2xpc3QkdDMkSm9pbnRNX2RlbnNpdHkkeCksCiAgZGVuc2l0eSA9IGMoTUxfUkVTVUxUU19TRVZFUkFMJGRlbnNpdGllc195JERlbnNpdHlfeXQzJHksIAogICAgICAgICAgICBNTF9SRVNVTFRTX1NFVkVSQUwkZGVuc2l0aWVzX01MX2xpc3QkdDMkTEFTU09fZGVuc2l0eSR5LCAKICAgICAgICAgICAgTUxfUkVTVUxUU19TRVZFUkFMJGRlbnNpdGllc19NTF9saXN0JHQzJFJGX2RlbnNpdHkkeSwgCiAgICAgICAgICAgIE1MX1JFU1VMVFNfU0VWRVJBTCRkZW5zaXRpZXNfTUxfbGlzdCR0MyRYZ0JfZGVuc2l0eSR5LAogICAgICAgICAgICBNTF9SRVNVTFRTX1NFVkVSQUwkZGVuc2l0aWVzX01MX2xpc3QkdDMkS2VybmVsS25uX2RlbnNpdHkkeSwKICAgICAgICAgICAgTUxfUkVTVUxUU19TRVZFUkFMJGRlbnNpdGllc19NTF9saXN0JHQzJEpvaW50TV9kZW5zaXR5JHkpLAogIG1vZGVsID0gZmFjdG9yKHJlcChsaXN0X21vZGVscywgdGltZXMgPSBzYXBwbHkobGlzdCgKICAgIE1MX1JFU1VMVFNfU0VWRVJBTCRkZW5zaXRpZXNfeSREZW5zaXR5X3l0MywKICAgIE1MX1JFU1VMVFNfU0VWRVJBTCRkZW5zaXRpZXNfTUxfbGlzdCR0MyRMQVNTT19kZW5zaXR5LCAKICAgIE1MX1JFU1VMVFNfU0VWRVJBTCRkZW5zaXRpZXNfTUxfbGlzdCR0MyRSRl9kZW5zaXR5LCAKICAgIE1MX1JFU1VMVFNfU0VWRVJBTCRkZW5zaXRpZXNfTUxfbGlzdCR0MyRYZ0JfZGVuc2l0eSwKICAgIE1MX1JFU1VMVFNfU0VWRVJBTCRkZW5zaXRpZXNfTUxfbGlzdCR0MyRLZXJuZWxLbm5fZGVuc2l0eSwKICAgIE1MX1JFU1VMVFNfU0VWRVJBTCRkZW5zaXRpZXNfTUxfbGlzdCR0MyRKb2ludE1fZGVuc2l0eQogICksIGZ1bmN0aW9uKGQpIGxlbmd0aChkJHgpKSkpCikKCiMgUGxvdCBzdXBlcmltcG9zZWQgZGVuc2l0eSBjdXJ2ZXMKZ2dwbG90KFRvUGxvdERhdGFfZGVuc2l0aWVzX3QzLCBhZXMoeCA9IHZhbHVlLCB5ID0gZGVuc2l0eSwgY29sb3IgPSBtb2RlbCkpICsKICBnZW9tX2xpbmUobGluZXdpZHRoID0gMC4yNSkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh0aXRsZSA9ICJEZW5zaXR5IG9mIHRoZSBkaWZmZXJlbnQgbW9kZWxzIHBlcmlvZCAzIiwgeCA9ICJWYWx1ZXMiLCB5ID0gIkRlbnNpdHkiKSArCiAgc2NhbGVfY29sb3JfZGlzY3JldGUobmFtZSA9ICJNb2RlbCIpCgojIERlZmluZSB0aGUgcGF0aCBmb3IgdGhlIFBORyBpbWFnZQpEZW5zaXRpZXNfdDMgPC0gIi9Vc2Vycy9ib25qb3VyL0RvY3VtZW50cy9NYXN0ZXIgaW4gRWNvbm9taWNzIEJvbm4vNXRoIHNlbWVzdGVyL1RoZXNpcy9SLUNvZGUvRHJhZnRzLzExdGggRHJhZnQgLSBBZHZhbmNlZCBmdW5jdGlvbiBhbmQgTW9udGVjYXJsby9JbWFnZXMvRGVuc2l0aWVzX3QzLnBuZyIKCiMgU2F2ZSB0aGUgZ2dwbG90IGFzIGEgUE5HIGltYWdlCmdnc2F2ZShmaWxlbmFtZSA9IERlbnNpdGllc190MywgcGxvdCA9IGxhc3RfcGxvdCgpLCB3aWR0aCA9IDYsIGhlaWdodCA9IDQsIGRwaSA9IDMwMCkKYGBgCjR0aCBwZXJpb2QKYGBge3J9CiMgVmFsdWVzIG9mIHRoZSBkZW5zaXRpZXMKVG9QbG90RGF0YV9kZW5zaXRpZXNfdDQgPC0gZGF0YS5mcmFtZSgKICB2YWx1ZSA9IGMoTUxfUkVTVUxUU19TRVZFUkFMJGRlbnNpdGllc195JERlbnNpdHlfeXQ0JHgsIAogICAgICAgICAgICBNTF9SRVNVTFRTX1NFVkVSQUwkZGVuc2l0aWVzX01MX2xpc3QkdDQkTEFTU09fZGVuc2l0eSR4LCAKICAgICAgICAgICAgTUxfUkVTVUxUU19TRVZFUkFMJGRlbnNpdGllc19NTF9saXN0JHQ0JFJGX2RlbnNpdHkkeCwgCiAgICAgICAgICAgIE1MX1JFU1VMVFNfU0VWRVJBTCRkZW5zaXRpZXNfTUxfbGlzdCR0NCRYZ0JfZGVuc2l0eSR4LAogICAgICAgICAgICBNTF9SRVNVTFRTX1NFVkVSQUwkZGVuc2l0aWVzX01MX2xpc3QkdDQkS2VybmVsS25uX2RlbnNpdHkkeCwKICAgICAgICAgICAgTUxfUkVTVUxUU19TRVZFUkFMJGRlbnNpdGllc19NTF9saXN0JHQ0JEpvaW50TV9kZW5zaXR5JHgpLAogIGRlbnNpdHkgPSBjKE1MX1JFU1VMVFNfU0VWRVJBTCRkZW5zaXRpZXNfeSREZW5zaXR5X3l0NCR5LCAKICAgICAgICAgICAgTUxfUkVTVUxUU19TRVZFUkFMJGRlbnNpdGllc19NTF9saXN0JHQ0JExBU1NPX2RlbnNpdHkkeSwgCiAgICAgICAgICAgIE1MX1JFU1VMVFNfU0VWRVJBTCRkZW5zaXRpZXNfTUxfbGlzdCR0NCRSRl9kZW5zaXR5JHksIAogICAgICAgICAgICBNTF9SRVNVTFRTX1NFVkVSQUwkZGVuc2l0aWVzX01MX2xpc3QkdDQkWGdCX2RlbnNpdHkkeSwKICAgICAgICAgICAgTUxfUkVTVUxUU19TRVZFUkFMJGRlbnNpdGllc19NTF9saXN0JHQ0JEtlcm5lbEtubl9kZW5zaXR5JHksCiAgICAgICAgICAgIE1MX1JFU1VMVFNfU0VWRVJBTCRkZW5zaXRpZXNfTUxfbGlzdCR0NCRKb2ludE1fZGVuc2l0eSR5KSwKICBtb2RlbCA9IGZhY3RvcihyZXAobGlzdF9tb2RlbHMsIHRpbWVzID0gc2FwcGx5KGxpc3QoCiAgICBNTF9SRVNVTFRTX1NFVkVSQUwkZGVuc2l0aWVzX3kkRGVuc2l0eV95dDQsCiAgICBNTF9SRVNVTFRTX1NFVkVSQUwkZGVuc2l0aWVzX01MX2xpc3QkdDQkTEFTU09fZGVuc2l0eSwgCiAgICBNTF9SRVNVTFRTX1NFVkVSQUwkZGVuc2l0aWVzX01MX2xpc3QkdDQkUkZfZGVuc2l0eSwgCiAgICBNTF9SRVNVTFRTX1NFVkVSQUwkZGVuc2l0aWVzX01MX2xpc3QkdDQkWGdCX2RlbnNpdHksCiAgICBNTF9SRVNVTFRTX1NFVkVSQUwkZGVuc2l0aWVzX01MX2xpc3QkdDQkS2VybmVsS25uX2RlbnNpdHksCiAgICBNTF9SRVNVTFRTX1NFVkVSQUwkZGVuc2l0aWVzX01MX2xpc3QkdDQkSm9pbnRNX2RlbnNpdHkKICApLCBmdW5jdGlvbihkKSBsZW5ndGgoZCR4KSkpKQopCgojIFBsb3Qgc3VwZXJpbXBvc2VkIGRlbnNpdHkgY3VydmVzCmdncGxvdChUb1Bsb3REYXRhX2RlbnNpdGllc190NCwgYWVzKHggPSB2YWx1ZSwgeSA9IGRlbnNpdHksIGNvbG9yID0gbW9kZWwpKSArCiAgZ2VvbV9saW5lKGxpbmV3aWR0aCA9IDAuMjUpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiRGVuc2l0eSBvZiB0aGUgZGlmZmVyZW50IG1vZGVscyBwZXJpb2QgNCIsIHggPSAiVmFsdWVzIiwgeSA9ICJEZW5zaXR5IikgKwogIHNjYWxlX2NvbG9yX2Rpc2NyZXRlKG5hbWUgPSAiTW9kZWwiKQoKIyBEZWZpbmUgdGhlIHBhdGggZm9yIHRoZSBQTkcgaW1hZ2UKRGVuc2l0aWVzX3Q0IDwtICIvVXNlcnMvYm9uam91ci9Eb2N1bWVudHMvTWFzdGVyIGluIEVjb25vbWljcyBCb25uLzV0aCBzZW1lc3Rlci9UaGVzaXMvUi1Db2RlL0RyYWZ0cy8xMXRoIERyYWZ0IC0gQWR2YW5jZWQgZnVuY3Rpb24gYW5kIE1vbnRlY2FybG8vSW1hZ2VzL0RlbnNpdGllc190NC5wbmciCgojIFNhdmUgdGhlIGdncGxvdCBhcyBhIFBORyBpbWFnZQpnZ3NhdmUoZmlsZW5hbWUgPSBEZW5zaXRpZXNfdDQsIHBsb3QgPSBsYXN0X3Bsb3QoKSwgd2lkdGggPSA2LCBoZWlnaHQgPSA0LCBkcGkgPSAzMDApCmBgYAo1dGggcGVyaW9kCmBgYHtyfQojIFZhbHVlcyBvZiB0aGUgZGVuc2l0aWVzClRvUGxvdERhdGFfZGVuc2l0aWVzX3Q1IDwtIGRhdGEuZnJhbWUoCiAgdmFsdWUgPSBjKE1MX1JFU1VMVFNfU0VWRVJBTCRkZW5zaXRpZXNfeSREZW5zaXR5X3l0NSR4LCAKICAgICAgICAgICAgTUxfUkVTVUxUU19TRVZFUkFMJGRlbnNpdGllc19NTF9saXN0JHQ1JExBU1NPX2RlbnNpdHkkeCwgCiAgICAgICAgICAgIE1MX1JFU1VMVFNfU0VWRVJBTCRkZW5zaXRpZXNfTUxfbGlzdCR0NSRSRl9kZW5zaXR5JHgsIAogICAgICAgICAgICBNTF9SRVNVTFRTX1NFVkVSQUwkZGVuc2l0aWVzX01MX2xpc3QkdDUkWGdCX2RlbnNpdHkkeCwKICAgICAgICAgICAgTUxfUkVTVUxUU19TRVZFUkFMJGRlbnNpdGllc19NTF9saXN0JHQ1JEtlcm5lbEtubl9kZW5zaXR5JHgsCiAgICAgICAgICAgIE1MX1JFU1VMVFNfU0VWRVJBTCRkZW5zaXRpZXNfTUxfbGlzdCR0NSRKb2ludE1fZGVuc2l0eSR4KSwKICBkZW5zaXR5ID0gYyhNTF9SRVNVTFRTX1NFVkVSQUwkZGVuc2l0aWVzX3kkRGVuc2l0eV95dDUkeSwgCiAgICAgICAgICAgIE1MX1JFU1VMVFNfU0VWRVJBTCRkZW5zaXRpZXNfTUxfbGlzdCR0NSRMQVNTT19kZW5zaXR5JHksIAogICAgICAgICAgICBNTF9SRVNVTFRTX1NFVkVSQUwkZGVuc2l0aWVzX01MX2xpc3QkdDUkUkZfZGVuc2l0eSR5LCAKICAgICAgICAgICAgTUxfUkVTVUxUU19TRVZFUkFMJGRlbnNpdGllc19NTF9saXN0JHQ1JFhnQl9kZW5zaXR5JHksCiAgICAgICAgICAgIE1MX1JFU1VMVFNfU0VWRVJBTCRkZW5zaXRpZXNfTUxfbGlzdCR0NSRLZXJuZWxLbm5fZGVuc2l0eSR5LAogICAgICAgICAgICBNTF9SRVNVTFRTX1NFVkVSQUwkZGVuc2l0aWVzX01MX2xpc3QkdDUkSm9pbnRNX2RlbnNpdHkkeSksCiAgbW9kZWwgPSBmYWN0b3IocmVwKGxpc3RfbW9kZWxzLCB0aW1lcyA9IHNhcHBseShsaXN0KAogICAgTUxfUkVTVUxUU19TRVZFUkFMJGRlbnNpdGllc195JERlbnNpdHlfeXQ1LAogICAgTUxfUkVTVUxUU19TRVZFUkFMJGRlbnNpdGllc19NTF9saXN0JHQ1JExBU1NPX2RlbnNpdHksIAogICAgTUxfUkVTVUxUU19TRVZFUkFMJGRlbnNpdGllc19NTF9saXN0JHQ1JFJGX2RlbnNpdHksIAogICAgTUxfUkVTVUxUU19TRVZFUkFMJGRlbnNpdGllc19NTF9saXN0JHQ1JFhnQl9kZW5zaXR5LAogICAgTUxfUkVTVUxUU19TRVZFUkFMJGRlbnNpdGllc19NTF9saXN0JHQ1JEtlcm5lbEtubl9kZW5zaXR5LAogICAgTUxfUkVTVUxUU19TRVZFUkFMJGRlbnNpdGllc19NTF9saXN0JHQ1JEpvaW50TV9kZW5zaXR5CiAgKSwgZnVuY3Rpb24oZCkgbGVuZ3RoKGQkeCkpKSkKKQoKIyBQbG90IHN1cGVyaW1wb3NlZCBkZW5zaXR5IGN1cnZlcwpnZ3Bsb3QoVG9QbG90RGF0YV9kZW5zaXRpZXNfdDUsIGFlcyh4ID0gdmFsdWUsIHkgPSBkZW5zaXR5LCBjb2xvciA9IG1vZGVsKSkgKwogIGdlb21fbGluZShsaW5ld2lkdGggPSAwLjI1KSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gIkRlbnNpdHkgb2YgdGhlIGRpZmZlcmVudCBtb2RlbHMgcGVyaW9kIDUiLCB4ID0gIlZhbHVlcyIsIHkgPSAiRGVuc2l0eSIpICsKICBzY2FsZV9jb2xvcl9kaXNjcmV0ZShuYW1lID0gIk1vZGVsIikKCiMgRGVmaW5lIHRoZSBwYXRoIGZvciB0aGUgUE5HIGltYWdlCkRlbnNpdGllc190NSA8LSAiL1VzZXJzL2JvbmpvdXIvRG9jdW1lbnRzL01hc3RlciBpbiBFY29ub21pY3MgQm9ubi81dGggc2VtZXN0ZXIvVGhlc2lzL1ItQ29kZS9EcmFmdHMvMTF0aCBEcmFmdCAtIEFkdmFuY2VkIGZ1bmN0aW9uIGFuZCBNb250ZWNhcmxvL0ltYWdlcy9EZW5zaXRpZXNfdDUucG5nIgoKIyBTYXZlIHRoZSBnZ3Bsb3QgYXMgYSBQTkcgaW1hZ2UKZ2dzYXZlKGZpbGVuYW1lID0gRGVuc2l0aWVzX3Q1LCBwbG90ID0gbGFzdF9wbG90KCksIHdpZHRoID0gNiwgaGVpZ2h0ID0gNCwgZHBpID0gMzAwKQpgYGAKCiMgMikgRFJERAoKUnVuIHRoZSBmb3JtdWxhCmBgYHtyfQpERFJEX3JlcyA8LSBEUkREX1JFU1VMVFMoTXlEYXRhLCBzdGFydGluZ190ZXN0X3BlcmlvZCwgZW5kaW5nX3Rlc3RfcGVyaW9kKQpgYGAKCjNyZCBwZXJpb2QgcmVzdWx0cwpgYGB7cn0KRERSRF90MyA8LSBERFJEX3JlcyREUkREX3QzCkREUkRfdDNfQVRUIDwtIEREUkRfdDMkQVRUCkREUkRfdDNfU0UgPC0gRERSRF90MyRzZQpERFJEX3QzX0NJIDwtIGNiaW5kKEREUkRfdDMkbGNpLCBERFJEX3QzJHVjaSkKYGBgCgo0dGggcGVyaW9kIHJlc3VsdHMKYGBge3J9CkREUkRfdDQgPC0gRERSRF9yZXMkRFJERF90NApERFJEX3Q0X0FUVCA8LSBERFJEX3Q0JEFUVApERFJEX3Q0X1NFIDwtIEREUkRfdDQkc2UKRERSRF90NF9DSSA8LSBjYmluZChERFJEX3Q0JGxjaSwgRERSRF90NCR1Y2kpCmBgYAoKNXRoIHBlcmlvZCByZXN1bHRzCmBgYHtyfQpERFJEX3Q1IDwtIEREUkRfcmVzJERSRERfdDUKRERSRF90NV9BVFQgPC0gRERSRF90NSRBVFQKRERSRF90NV9TRSA8LSBERFJEX3Q1JHNlCkREUkRfdDVfQ0kgPC0gY2JpbmQoRERSRF90NSRsY2ksIEREUkRfdDUkdWNpKQpgYGAKCkNyZWF0aW5nIHRoZSB0YWJsZSBhbmQgc2F2aW5nIHRoZSBpbWFnZQpgYGB7cn0KIyBDcmVhdGUgYSBkYXRhIGZyYW1lIHdpdGggdGhlIG51bWVyaWMgZWxlbWVudHMKRERSRF9kZiA8LSBkYXRhLmZyYW1lKAogIHQzID0gYyhERFJEX3QzX0FUVCwgRERSRF90M19TRSksCiAgdDQgPSBjKEREUkRfdDRfQVRULCBERFJEX3Q0X1NFKSwKICB0NSA9IGMoRERSRF90NV9BVFQsIEREUkRfdDVfU0UpLAogIGF2ZXJhZ2UgPSBjKHN1bShERFJEX3QzX0FUVCwgRERSRF90NF9BVFQsIEREUkRfdDVfQVRUKS8zLCBzdW0oRERSRF90M19TRSwgRERSRF90NF9TRSwgRERSRF90NV9TRSkvMykKKQoKIyBBZGQgcm93IG5hbWVzCnJvdy5uYW1lcyhERFJEX2RmKSA8LSBjKCJBVFQiLCAiU0UiKQoKIyBDcmVhdGUgYSBjb2RlIGZvciBhIExhVGVYIFRhYmxlCmxhdGV4X2NvZGVfQVRUX0RSREQgPC0geHRhYmxlKEREUkRfZGYsIGNhcHRpb24gPSAiRFJERCBBVFQgJiBTRSBwZXIgcGVyaW9kIGVzdGltYXRlZCIpCgojIFByaW50IHRoZSBMYVRlWCBjb2RlCnByaW50KGxhdGV4X2NvZGVfQVRUX0RSREQsIGluY2x1ZGUucm93bmFtZXMgPSBUUlVFKQoKIyAjIERlZmluZSB0aGUgdGl0bGUKIyB0aXRsZSA8LSAiRG91YmxlIFJvYnVzdCBEaWZmZXJlbmNlLWluIGRpZmZlcmVuY2VzIHBlciBwZXJpb2QiCiMgCiMgIyBTYXZlIGl0IGFzIGFuIElNQUdFCiMgCiMgIyAjIERlZmluZSB0aGUgZmlsZSBwYXRoIGZvciB0aGUgaW1hZ2UKIyBERFJEX3BhdGggPC0gIi9Vc2Vycy9ib25qb3VyL0RvY3VtZW50cy9NYXN0ZXIgaW4gRWNvbm9taWNzIEJvbm4vNXRoIHNlbWVzdGVyL1RoZXNpcy9SLUNvZGUvRHJhZnRzLzl0aCBEcmFmdC9HcmFwaHMgYW5kIHJlc3VsdHMvRERSRF90YWJsZS5wbmciCiMgCiMgIyBSZW5kZXIgdGhlIHRhYmxlIHdpdGggc3R5bGluZwojIEREUkRfaHRtbCA8LSBrYWJsZShERFJEX2RmLCBjYXB0aW9uID0gdGl0bGUsIGZvcm1hdCA9ICJodG1sIikgJT4lCiMgICAgICAgICAgICAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIiwgInJlc3BvbnNpdmUiKSkgJT4lCiMgICAgICAgICAgICAgcm93X3NwZWMoMCwgYmFja2dyb3VuZCA9ICJwaW5rIikgJT4lICAjIENvbG9yIHRoZSBoZWFkZXIgcm93CiMgICAgICAgICAgICAgcm93X3NwZWMoMTpucm93KEREUkRfZGYpLCBiYWNrZ3JvdW5kID0gImxpZ2h0Z3JheSIpICAjIENvbG9yIHRoZSBkYXRhIHJvd3MKIyAKIyAjIFNhdmUgdGhlIEhUTUwgY29udGVudCB0byBhIHRlbXBvcmFyeSBmaWxlCiMgdGVtcF9odG1sX0REUkQgPC0gdGVtcGZpbGUoZmlsZWV4dCA9ICIuaHRtbCIpCiMgd3JpdGVMaW5lcyhERFJEX2h0bWwsIHRlbXBfaHRtbF9ERFJEKQojIAojICMgU2F2ZSB0aGUgdGFibGUgYXMgYW4gaW1hZ2Ugd2l0aCBhIHRyYW5zcGFyZW50IGJhY2tncm91bmQKIyB3ZWJzaG90KHRlbXBfaHRtbF9ERFJELAojICAgICAgICAgZmlsZSA9IEREUkRfcGF0aCwKIyAgICAgICAgIHNlbGVjdG9yID0gIi50YWJsZSIsCiMgICAgICAgICB2d2lkdGggPSA4MDAsIHZoZWlnaHQgPSA0MDAsICAjIFNldCB3aWR0aCBhbmQgaGVpZ2h0IGFzIG5lZWRlZAojICAgICAgICAgZGVsYXkgPSAwLAojICAgICAgICAgem9vbSA9IDEsCiMgICAgICAgICApCgpgYGAKCkNyZWF0aW5nIGEgZ3JhcGggZm9yIHRoZSBjb25maWRlbmNlIGludGVydmFscwpgYGB7cn0KRGF0YV9wbG90X0RSRERfQ0kgPC0gZGF0YS5mcmFtZSgKICBwZXJpb2QgPSBjKCJQZXJpb2QgMyIsICJQZXJpb2QgNCIsICJQZXJpb2QgNSIpLAogIEFUVCA9IGMoRERSRF90M19BVFQsIEREUkRfdDRfQVRULCBERFJEX3Q1X0FUVCksCiAgTG93ZXJfQ0kgPSBjKEREUkRfdDNfQ0lbLCAxXSwgRERSRF90NF9DSVssIDFdLCBERFJEX3Q1X0NJWywgMV0pLAogIFVwcGVyX0NJID0gYyhERFJEX3QzX0NJWywgMl0sIEREUkRfdDRfQ0lbLCAyXSwgRERSRF90NV9DSVssIDJdKQopCgojIFRoZSBncmFwaApnZ3Bsb3QoRGF0YV9wbG90X0RSRERfQ0ksIGFlcyh4ID0gcGVyaW9kLCB5ID0gQVRUKSkgKwogIGdlb21fcG9pbnQoY29sb3IgPSAiYmx1ZSIsIHNpemUgPSAzKSArCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbiA9IExvd2VyX0NJLCB5bWF4ID0gVXBwZXJfQ0kpLCB3aWR0aCA9IDAuMiwgY29sb3IgPSAicmVkIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJBdmVyYWdlIFRyZWF0bWVudCBFZmZlY3QgKEFUVCkgYW5kIENvbmZpZGVuY2UgSW50ZXJ2YWxzIiwKICAgIHggPSAiUGVyaW9kIiwKICAgIHkgPSAiQVRUIgogICkgKwogIHRoZW1lX21pbmltYWwoKQoKIyBEZWZpbmUgdGhlIHBhdGggZm9yIHRoZSBQTkcgaW1hZ2UKRFJERF9DSSA8LSAiL1VzZXJzL2JvbmpvdXIvRG9jdW1lbnRzL01hc3RlciBpbiBFY29ub21pY3MgQm9ubi81dGggc2VtZXN0ZXIvVGhlc2lzL1ItQ29kZS9EcmFmdHMvMTJ0aCBEcmFmdC9JbWFnZXMvRFJERF9DSS5wbmciCgojIFNhdmUgdGhlIGdncGxvdCBhcyBhIFBORyBpbWFnZQpnZ3NhdmUoZmlsZW5hbWUgPSBEUkREX0NJLCBwbG90ID0gbGFzdF9wbG90KCksIHdpZHRoID0gNiwgaGVpZ2h0ID0gNCwgZHBpID0gMzAwKQoKYGBgCgoKCiMgTEVUJ1MgVFJZIEEgTU9OVEVDQVJMTyBTSU1VTEFUSU9OICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgojIEdlbmVhcnRpbmcgdGhlIGRhdGEKCmBgYHtyfQpkYXRhLmdlbmVyYXRvcl9NQyA8LSBmdW5jdGlvbihuLCBzaWdtYSwgbXUsIGJldGEudHJ1ZSwgYmV0YS5kLCBwcm9iYWJpbGl0eSwgc2VlZCA9IE5VTEwpewogIAogICMgU2V0IHRoZSBzZWVkIGlmIHByb3ZpZGVkCiAgaWYgKCFpcy5udWxsKHNlZWQpKSBzZXQuc2VlZChzZWVkKQogIAogICMgWHMgYW5kIGVycm9ycyBmb3IgNSBwZXJpb2RzCiAgCiAgIyBDcmVhdGUgYW4gZW1wdHkgbGlzdCB0byBzdG9yZSB0aGUgdmVjdG9ycwogIHhfdF9saXN0IDwtIGxpc3QoKQogIGVfdF9saXN0IDwtIGxpc3QoKQogIAogICMgR2VuZXJhdGUgdGhlIHZlY3RvcnMgd2l0aGluIHRoZSBsb29wIGFuZCBzdG9yZSB0aGVtIGluIHRoZSBsaXN0IHdpdGggdGhlaXIgcmVzcGVjdGl2ZSB0aW1lcwogIGZvciAoaSBpbiAxOjUpIHsKICAgIHhfdGkgPC0gbXZybm9ybShuLCBtdSwgc2lnbWEpCiAgICB4X3RfbGlzdFtbcGFzdGUwKCJ4X3QiLCBpKV1dIDwtIHhfdGkKICAgIGVfdGkgPC0gcm5vcm0obiwgMCwgc3FydCgxMCkpCiAgICBlX3RfbGlzdFtbcGFzdGUwKCJlX3QiLCBpKV1dIDwtIGVfdGkKICB9CgogICMgR2VuZXJhdGUgdGhlIGQgZm9yIDUgcGVyaW9kcwogIGRfdDEgPC0gcmVwKDAsIG4pCiAgZF90MiA8LSByZXAoMCwgbikKICBkX3QzIDwtIHNhbXBsZShjKDAsIDEpLCBzaXplID0gbiwgcmVwbGFjZSA9IFRSVUUpCiAgZF90NCA8LSBpZmVsc2UoZF90MyA9PSAxIHwgcnVuaWYobGVuZ3RoKGRfdDMpKSA8IHByb2JhYmlsaXR5LCAxLCAwKQogIGRfdDUgPC0gaWZlbHNlKGRfdDQgPT0gMSB8IHJ1bmlmKGxlbmd0aChkX3Q0KSkgPCBwcm9iYWJpbGl0eSwgMSwgMCkKICBkIDwtIGNiaW5kKGRfdDEsIGRfdDIsIGRfdDMsIGRfdDQsIGRfdDUpCiAgCiAgIyBHZW5lcmF0ZSB0aGUgeXMgLS0tLS0tLS0tLS0tLS0KICAKICAjIEJlZm9yZSB0cmVhdG1lbnQKICB5X3QxIDwtIHhfdF9saXN0W1sieF90MSJdXSAlKiUgYmV0YS50cnVlWywxXSArIGVfdF9saXN0W1siZV90MSJdXQogIHlfdDIgPC0geF90X2xpc3RbWyJ4X3QyIl1dICUqJSBiZXRhLnRydWVbLDJdICsgZV90X2xpc3RbWyJlX3QyIl1dCiAgIyBBZnRlciB0cmVhdG1lbnQKICB5X3QzIDwtIGRfdDMqYmV0YS5kWzFdICsgeF90X2xpc3RbWyJ4X3QzIl1dICUqJSBiZXRhLnRydWVbLDNdICsgZV90X2xpc3RbWyJlX3QzIl1dCiAgeV90NCA8LSBkX3QzKmJldGEuZFsyXSArIHhfdF9saXN0W1sieF90NCJdXSAlKiUgYmV0YS50cnVlWyw0XSArIGVfdF9saXN0W1siZV90NCJdXQogIHlfdDUgPC0gZF90MypiZXRhLmRbM10gKyB4X3RfbGlzdFtbInhfdDUiXV0gJSolIGJldGEudHJ1ZVssNV0gKyBlX3RfbGlzdFtbImVfdDUiXV0KICB5IDwtIGNiaW5kKHlfdDEsIHlfdDIsIHlfdDMsIHlfdDQsIHlfdDUpCiAgCiAgI1N0YW5kYXJkaXplIFhzCiAgCiAgIyBJbml0aWFsaXplIHRoZSBsaXN0IHRvIHN0b3JlIHN0YW5kYXJkaXplZCBtYXRyaWNlcwogIHhfdF9saXN0LnNkIDwtIGxpc3QoKQogIAogIGZvciAodmFyaWFibGUgaW4gbmFtZXMoeF90X2xpc3QpKSB7CiAgICAjRGVmaW5pbmcgdGhlIG1hdHJpY2VzCiAgICB4X3RfbGlzdC5zZFtbcGFzdGUwKHZhcmlhYmxlLCAiLnNkIildXSA8LSBtYXRyaXgoTkEsIG5yb3cgPSBucm93KHhfdF9saXN0W1t2YXJpYWJsZV1dKSwgbmNvbCA9IG5jb2woeF90X2xpc3RbW3ZhcmlhYmxlXV0pKQogICAgI1N0YXJ0aW5nIHRoZSBzdGFuZGFyZGl6YXRpb24KICAgIGZvciAoaSBpbiAxOm5jb2woeF90X2xpc3Quc2RbW3Bhc3RlMCh2YXJpYWJsZSwgIi5zZCIpXV0pKXsKICAgIHhfdF9saXN0LnNkW1twYXN0ZTAodmFyaWFibGUsICIuc2QiKV1dWywgaV0gPC0gKHhfdF9saXN0W1t2YXJpYWJsZV1dWywgaV0gLSBtZWFuKHhfdF9saXN0W1t2YXJpYWJsZV1dWywgaV0pKSAvIHNkKHhfdF9saXN0W1t2YXJpYWJsZV1dWywgaV0pCiAgICB9CiAgfQogIAogIGRhdGEgPC0gZGF0YS5mcmFtZSAoInkiID0geSwgImQiID0gZCwgIngiID0geF90X2xpc3QsICJ4LnNkIiA9IHhfdF9saXN0LnNkKQogIHJldHVybihkYXRhKQp9CmBgYAoKIyBTaW11bGF0aW9ucyBvZiB0aGUgTUwgbW9kZWwgZnVuY3Rpb24KYGBge3J9Ck1vbnRlQ2FybG9fTUwgPC0gZnVuY3Rpb24obiwgc2lnbWEsIG11LCBiZXRhLnRydWUsIGJldGEuZCwgcHJvYmFiaWxpdHksCiAgICAgICAgICAgICAgICAgICAgICAgbnVtX3NpbXVsYXRpb25zLAogICAgICAgICAgICAgICAgICAgICAgIENWX251bV9mb2xkcywgc3RhcnRpbmdfdGVzdF9wZXJpb2QsIGVuZGluZ190ZXN0X3BlcmlvZCwgbW9kZWxzLCBtb2RlbHNfbmFtZXMpewogIAojIExpc3QgdG8gc3RvcmUgdGhlIHZhbHVlcwogIApTaW11bGF0aW9uX3Jlc3VsdHMgPC0gbGlzdCgpCgojIFNldHRpbmcgYSB2YXJpYWJsZSBzZWVkICAgIApmb3IgKGkgaW4gMTpudW1fc2ltdWxhdGlvbnMpIHsKICAKICAjIFVzZSBhIGRpZmZlcmVudCBzZWVkIGZvciBlYWNoIHNpbXVsYXRpb24KICBzZWVkIDwtIGkKICBzaW11bGF0ZWRfZGF0YSA8LSBkYXRhLmdlbmVyYXRvcl9NQyhuLCBzaWdtYSwgbXUsIGJldGEudHJ1ZSwgYmV0YS5kLCBwcm9iYWJpbGl0eSwgc2VlZCkKICAKICAjIFRoZW4gYXBwbHkgb3VyIGZ1bmN0aW9uCiAgU2ltdWxhdGlvbl9yZXN1bHRzW1twYXN0ZSgiU2ltdWxhdGlvbiIsIGksIHNlcCA9ICIiKV1dIDwtIEFUVF9NTF9nZW5lcmF0b3JfQURWQU5DRUQoc2ltdWxhdGVkX2RhdGEsIENWX251bV9mb2xkcywgc3RhcnRpbmdfdGVzdF9wZXJpb2QsIGVuZGluZ190ZXN0X3BlcmlvZCwgbW9kZWxzLCBtb2RlbHNfbmFtZXMpCgp9CgpyZXR1cm4oU2ltdWxhdGlvbl9yZXN1bHRzKQogIAp9CmBgYAoKIyBTaW11bGF0aW9ucyBvZiB0aGUgRFJERCBtb2RlbCBmdW5jdGlvbgpgYGB7cn0KTW9udGVDYXJsb19EUkREIDwtIGZ1bmN0aW9uKG4sIHNpZ21hLCBtdSwgYmV0YS50cnVlLCBiZXRhLmQsIHByb2JhYmlsaXR5LAogICAgICAgICAgICAgICAgICAgICAgIG51bV9zaW11bGF0aW9ucywKICAgICAgICAgICAgICAgICAgICAgICBzdGFydGluZ190ZXN0X3BlcmlvZCwgZW5kaW5nX3Rlc3RfcGVyaW9kKXsKICAKIyBMaXN0IHRvIHN0b3JlIHRoZSB2YWx1ZXMKICAKU2ltdWxhdGlvbl9yZXN1bHRzIDwtIGxpc3QoKQoKIyBTZXR0aW5nIGEgdmFyaWFibGUgc2VlZCAgICAKZm9yIChpIGluIDE6bnVtX3NpbXVsYXRpb25zKSB7CiAgCiAgIyBVc2UgYSBkaWZmZXJlbnQgc2VlZCBmb3IgZWFjaCBzaW11bGF0aW9uCiAgc2VlZCA8LSBpCiAgc2ltdWxhdGVkX2RhdGEgPC0gZGF0YS5nZW5lcmF0b3JfTUMobiwgc2lnbWEsIG11LCBiZXRhLnRydWUsIGJldGEuZCwgcHJvYmFiaWxpdHksIHNlZWQpCiAgCiAgIyBUaGVuIGFwcGx5IG91ciBmdW5jdGlvbgogIFNpbXVsYXRpb25fcmVzdWx0c1tbcGFzdGUoIlNpbXVsYXRpb24iLCBpLCBzZXAgPSAiIildXSA8LSBEUkREX1JFU1VMVFMoc2ltdWxhdGVkX2RhdGEsIHN0YXJ0aW5nX3Rlc3RfcGVyaW9kLCBlbmRpbmdfdGVzdF9wZXJpb2QpCn0KCnJldHVybihTaW11bGF0aW9uX3Jlc3VsdHMpCiAgCn0KYGBgCgoKUGFyYW1ldGVycyB0byBiZSB1c2VkIGZvciBib3RoIG9mIHRoZW0KYGBge3J9CiMgUGFyYW1ldGVycyBmaXJzdCBmdW5jdGlvbgpuIDwtIDEwMDAgI2luZGl2aWR1YWxzCmJldGEuZCA8LSBjKDAuMywgMC40LCAwLjUpICMgYmV0YSAiZCIgZm9yIDMgZGlmZmVyZW50IHBlcmlvZHMKYmV0YS50cnVlIDwtIG1hdHJpeChjKC0wLjUsMC4xLDAuNSwwLjUsLTAuNSwKICAgICAgICAgICAgICAgICAgICAgIC0wLjYsMC4yLDAuNiwwLjUsLTAuNSwKICAgICAgICAgICAgICAgICAgICAgIC0wLjgsMC40LDAuNiwwLjksLTAuOCwKICAgICAgICAgICAgICAgICAgICAgIC0wLjgsMC41LDAuNywwLjksLTEuMCwKICAgICAgICAgICAgICAgICAgICAgIC0wLjksMC43LDAuNywxLjAsLTEuMCksbnJvdz0gNSwgbmNvbD0gNSwgYnlyb3c9VFJVRSkgIyBiZXRhcyAiWCIgZm9yIDUgZGlmZmVyZW50IHBlcmlvZHMKc2lnbWEgPC0gbWF0cml4KGMoMSwwLjEsMC4xLDAuMSwwLjEsCiAgICAgICAgICAgICAgICAgIDAuMSwyLDAuMSwwLjEsMC4xLAogICAgICAgICAgICAgICAgICAwLjEsMC4xLDMsMC4xLDAuMSwKICAgICAgICAgICAgICAgICAgMC4xLDAuMSwwLjEsNCwwLjEsCiAgICAgICAgICAgICAgICAgIDAuMSwwLjEsMC4xLDAuMSw1KSAsbnJvdz0gNSwgbmNvbD0gNSwgYnlyb3c9VFJVRSkgIyB3ZSB3aWxsIGtlZXAgdGhlIHNhbWUgdmFyaWFuY2UgdGhyb3VnaCB0aW1lCm11IDwtIHJlcCgwLDUpICMgdGhlIG1lYW4gd2lsbCBiZSB6ZXJvIHRocm91Z2ggdGltZQpwcm9iYWJpbGl0eSA8LSAwLjUgICMgUHJvYmFiaWxpdHkgb2YgcmVwbGFjaW5nIHRoZSAwJ3Mgd2l0aCBvbmVzIGFmdGVyIGVhY2ggcGVyaW9kCgojIG51bWJlciBvZiBzaW11bGF0aW9ucwpudW1fc2ltdWxhdGlvbnMgPC0gMTAwCgojIHBhcmFtZXRlcnMgMm5kIGZ1bmN0aW9uCkNWX251bV9mb2xkcyA9IDEwICMgb3Igd2hhdGV2ZXIgbWF5IGJlIGRlY2lkZWQKc3RhcnRpbmdfdGVzdF9wZXJpb2QgPSAzICMgY2FuIGJlIGFkYXB0ZWQgZGVwZW5kaW5nIG9uIHRoZSBzdGFydGluZyB0cmVhdG1lbnQgcGVyaW9kIG9mIHlvdXIgZGF0YWJhc2UKZW5kaW5nX3Rlc3RfcGVyaW9kID0gNSAjIGNhbiBiZSBhZGFwdGVkIGRlcGVuZGluZyBvbiB0aGUgZW5kaW5nIHRyZWF0bWVudCBwZXJpb2Qgb2YgeW91ciBkYXRhYmFzZQptb2RlbHMgPC0gYygiU0wuZ2xtbmV0IiwgIlNMLnJhbmRvbUZvcmVzdCIsICJTTC54Z2Jvb3N0IiwgIlNMLmtlcm5lbEtubiIpICMgY2FuIGJlIGFkYXB0ZWQgZ2l2ZW4gdGhlIG1vZGVscyB0aGF0IHlvdSB3aWxsIGJlIHVzaW5nCm1vZGVsc19uYW1lcyA8LSBjKCJMQVNTTyIsICJSRiIsICJYZ0IiLCAiS2VybmVsS25uIikgIyBjYW4gYmUgYWRhcHRlZCBnaXZlbiB0aGUgbW9kZWxzIHRoYXQgeW91IHdpbGwgYmUgdXNpbmcKYGBgCgoKCiMgUkVTVUxUUyBPRiBUSEUgTUwgU0lNVUxBVElPTlMKR2V0dGluZyBvdXIgcmVzdWx0cwpgYGB7cn0KTW9udGVDYXJsb19yZXN1bHRzIDwtIE1vbnRlQ2FybG9fTUwobiwgc2lnbWEsIG11LCBiZXRhLnRydWUsIGJldGEuZCwgcHJvYmFiaWxpdHksCiAgICAgICAgICAgICAgICAgICAgICAgbnVtX3NpbXVsYXRpb25zLAogICAgICAgICAgICAgICAgICAgICAgIENWX251bV9mb2xkcywgc3RhcnRpbmdfdGVzdF9wZXJpb2QsIGVuZGluZ190ZXN0X3BlcmlvZCwgbW9kZWxzLCBtb2RlbHNfbmFtZXMpCmBgYAoKTm93IGFzIHZlY3RvcnMsIG1heSBiZSBiZXR0ZXIgdG8gZ3JhcGggdGhlbQpgYGB7cn0Kc3RhdGlzdGljc19uYW0gPC0gYygiQVRUIiwgIk1BRSIsICJNU0UiLCAiUjIiKQoKbW9kZWxzX3VwIDwtIGMobW9kZWxzX25hbWVzLCAiSm9pbnRNIikKCiMgQ3JlYXRlIGFuIGVtcHR5IGxpc3QgZm9yIGVhY2ggc3RhdGlzdGljCk1DX3Blcl9zdGF0aXN0aWMgPC0gbGFwcGx5KHNldE5hbWVzKHZlY3RvcignbGlzdCcsIGxlbmd0aChzdGF0aXN0aWNzX25hbSkpLCBzdGF0aXN0aWNzX25hbSksIGZ1bmN0aW9uKHgpIHNldE5hbWVzKHZlY3RvcignbGlzdCcsIGxlbmd0aChtb2RlbHNfdXApKSwgbW9kZWxzX3VwKSkKCmZvciAocyBpbiBzdGF0aXN0aWNzX25hbSkgewogIAogIGZvciAobSBpbiBtb2RlbHNfdXApIHsKICAgIHZlY3Rvcl9uYW1lIDwtIHBhc3RlKCJNQ19hdmVyYWdlX3ZhbHVlcyIsIHMsIG0sIHNlcCA9ICJfIikKICAgIAogICAgZm9yIChpIGluIDE6bnVtX3NpbXVsYXRpb25zKSB7CiAgICAgICMgTnVtYmVyIG9mIHNpbXVsYXRpb24KICAgICAgc2ltdWxhdGlvbl9uYW1lIDwtIHBhc3RlKCJTaW11bGF0aW9uIiwgaSwgc2VwID0gIiIpCiAgICAgIAogICAgICAjIEZpbGwgdGhlIHZlY3RvciB3aXRoIHRoZSBjb3JyZWN0IHZhbHVlcwogICAgICBNQ19wZXJfc3RhdGlzdGljW1tzXV1bW21dXSA8LSBjKE1DX3Blcl9zdGF0aXN0aWNbW3NdXVtbbV1dLCBNb250ZUNhcmxvX3Jlc3VsdHNbW3NpbXVsYXRpb25fbmFtZV1dJGF2ZXJhZ2VfdmFsdWVzW1tzXV1bW3Bhc3RlKHMsIG0sICJhdmVyYWdlIiwgc2VwID0gIl8iKV1dKQogICAgfQogIH0KfQoKIyBOb3csIE1DX3Blcl9zdGF0aXN0aWMgaXMgYSBuZXN0ZWQgbGlzdCB3aGVyZSBlYWNoIG91dGVyIGVsZW1lbnQgcmVwcmVzZW50cyBhIHN0YXRpc3RpYywgZWFjaCBpbm5lciBlbGVtZW50IHJlcHJlc2VudHMgYSBtb2RlbCwgYW5kIGNvbnRhaW5zIGEgdmVjdG9yIG9mIHZhbHVlcyBmb3IgZWFjaCBtb2RlbCBhbmQgc3RhdGlzdGljLgpgYGAKCkxldCdzIGdldCB0aGUgQVRUIGZvciBlYWNoIHBlcmlvZCBmb3IgdGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzCmBgYHtyfQpwZXJpb2RzX3VzZWQgPC0gYygiUGVyaW9kXzMiLCAiUGVyaW9kXzQiLCAiUGVyaW9kXzUiKQoKbW9kZWxzX3VwICNsZXQncyB1c2Ugb3VyIHZhcmlhYmxlIG1vZGVscyB1cAoKZm9yIChtIGluIG1vZGVsc191cCkgewoKICBBVFRfTUNfcGVyLnBlcmlvZCA8LSBwYXN0ZSgiQVRUX01DX3Blci5wZXJpb2QiLCBtLCBzZXAgPSAiLiIpCiAgYXNzaWduKEFUVF9NQ19wZXIucGVyaW9kLCBtYXRyaXgoTkEsIG51bV9zaW11bGF0aW9ucywgbGVuZ3RoKHBlcmlvZHNfdXNlZCkpKQoKICBmb3IgKGkgaW4gMTpudW1fc2ltdWxhdGlvbnMpIHsKCiAgICBmb3IgKHBfaW5kZXggaW4gc2VxX2Fsb25nKHBlcmlvZHNfdXNlZCkpIHsKCiAgICAgICMgVG8gZ2V0IHRoZSB2YWx1ZSBvZiBwZXJpb2RzIHVzZWQsIHRoZSBlbGVtZW50IGl0c2VsZgogICAgICBwIDwtIHBlcmlvZHNfdXNlZFtwX2luZGV4XQoKICAgICAgIyBFeHRyYWN0IHRoZSBsYXN0IGNoYXJhY3RlciBmcm9tIHRoZSBwZXJpb2QKICAgICAgcGVyaW9kX2RpZ2l0IDwtIHN1YnN0cihwLCBuY2hhcihwKSwgbmNoYXIocCkpCgogICAgICAjIEZvcm0gdGhlIG1vZGVsIG5hbWUKICAgICAgbW9kZWxfbmFtZSA8LSBwYXN0ZShtLCAiX3QiLCBwZXJpb2RfZGlnaXQsIHNlcCA9ICIiKQoKICAgICAgIyBVc2UgYSB0ZW1wb3JhcnkgdmFyaWFibGUgdG8gcmVmZXJlbmNlIHRoZSBtYXRyaXgKICAgICAgdGVtcF9tYXRyaXggPC0gZ2V0KEFUVF9NQ19wZXIucGVyaW9kKQogICAgICAKICAgICAgIyBVcGRhdGUgdGhlIG1hdHJpeCB1c2luZyB0aGUgY29ycmVjdCBpbmRleGluZwogICAgICB0ZW1wX21hdHJpeFtpLCBwX2luZGV4XSA8LSBNb250ZUNhcmxvX3Jlc3VsdHNbW3Bhc3RlKCJTaW11bGF0aW9uIiwgaSwgc2VwID0gIiIpXV0kRml0bmVzc1N0YXRpc3RpY3MkQVRUW1twXV1bW21vZGVsX25hbWVdXQoKICAgICAgIyBBc3NpZ24gdGhlIG1hdHJpeCB0byB0aGUgdmFyaWFibGUKICAgICAgYXNzaWduKEFUVF9NQ19wZXIucGVyaW9kLCB0ZW1wX21hdHJpeCkKICAgIH0KCiAgfQoKfQoKYGBgCgoKIyMjIENPTkZJREVOQ0UgSU5URVJWQUxTIEZVTkNUSU9OICMjIyBGb3IgcmVhbCBkYXRhIHdlIGNhbiB1c2UgYSBib290c3RyYXAgc2ltdWxhdGlvbiB0byBnZXQgdGhlbQoKV2l0aCBhdmVyYWdlcyBpbiB0aGUgbWlkZGxlCmBgYHtyfQojIElOUFVUUwojIGNvbmZpZGVuY2VfbGV2ZWwgPC0gMC45NQojIHN0YXRpc3RpYyA8LSBBVFRfTUNfcGVyLnBlcmlvZC5Kb2ludE0sIEFUVF9NQ19wZXIucGVyaW9kLktlcm5lbEtubiwgQVRUX01DX3Blci5wZXJpb2QuTEFTU08sIEFUVF9NQ19wZXIucGVyaW9kLlJGLCBBVFRfTUNfcGVyLnBlcmlvZC5YZ0IKIyBudW1fcGVyaW9kcyA8LSAzCiMgcGVyaW9kX3RyZWF0bWVudCA8LSAzIGZpcnN0IHdoZW4gdGhlIHRyZWF0bWVudCBzdGFydHMKCkNvbmZpZGVuY2VfaW50ZXJ2YWxzIDwtIGZ1bmN0aW9uKGNvbmZpZGVuY2VfbGV2ZWwsIHN0YXRpc3RpYywgbnVtX3BlcmlvZHMsIHBlcmlvZF90cmVhdG1lbnQpewogIAogICMgQmFzZWQgb24gdGhlIHBlcmlvZF90cmVhdG1lbnQKICBmb3JfbGlzdCA8LSBwZXJpb2RfdHJlYXRtZW50IC0gMQogIAogICMjIyMjIFRvIHN0b3JlIHRoZSBjb25maWRlbmNlIGludGVydmFscyBmb3IgZWFjaCBwZXJpb2QKICAKICAjIFRvIGV4dHJhY3QgdGhlIHRleHQgYWZ0ZXIgdGhlIGxhc3QgcG9pbnQKICBleHRyYWN0X2xhc3RfdGV4dCA8LSBmdW5jdGlvbihTdHJpbmdfdXNlKSB7CiAgICB0ZXh0IDwtIGdzdWIoIi4qXFwuKFxcRCspJCIsICJcXDEiLCBzKQogICAgdGV4dAogIH0KICAKICAjIENvbnZlcnQgdGhlIHN0YXRpc3RpYyB0byBhIHN0cmluZyBmb3IgdXNhZ2UKICBTdHJpbmdfdXNlIDwtIGFzLmNoYXJhY3RlcihBVFRfTUNfcGVyLnBlcmlvZC5Kb2ludE0pCiAgCiAgIyBBcHBseSB0aGUgZXh0cmFjdF9sYXN0X3RleHQgZnVuY3Rpb24gdG8gZ2V0IHRoZSBkZXNpcmVkIHRleHQKICBsYXN0X3RleHQgPC0gZXh0cmFjdF9sYXN0X3RleHQoU3RyaW5nX3VzZSkKICAKICAjIyMjIyBUbyBzdG9yZSB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbHMgZm9yIGVhY2ggcGVyaW9kCiAgCiAgIyBGaXJzdCBhc3NpZ24gdGhlIG5hbWUKICBDSV9wcmVmaXggPC0gcGFzdGUoIkNJXyIsIGxhc3RfdGV4dCwgc2VwID0gIiIpCgogICMgTm93IGFzc2lnbiB0aGUgdmFsdWUKICBhc3NpZ24oQ0lfcHJlZml4LCBsaXN0KCkpCgogICMgTG9vcCBvdmVyIGVhY2ggbW9kZWwKICBmb3IgKG4gaW4gMTpudW1fcGVyaW9kcykgewogICAgCiAgICAjIEdldCB0aGUgYXZlcmFnZXMKICAgIGF2ZXJhZ2UgPC0gbWVhbihzdGF0aXN0aWNbLCBuXSkKICAKICAgICMgRXh0cmFjdCBBVFQgdmFsdWVzIGZvciB0aGUgY3VycmVudCBtb2RlbAogICAgYXR0X21vZGVsIDwtIHN0YXRpc3RpY1ssIG5dICMgdG8gZ2V0IHRoZSByZXNwZWN0aXZlIGNvbHVtbiB2YWx1ZXMKICAKICAgICMgQ29tcHV0ZSBjb25maWRlbmNlIGludGVydmFsIG1hbnVhbGx5CiAgICBzZSA8LSBzZChhdHRfbW9kZWwpIC8gc3FydChsZW5ndGgoYXR0X21vZGVsKSkKICAgIG1hcmdpbl9lcnJvciA8LSBxdCgoMSArIGNvbmZpZGVuY2VfbGV2ZWwpIC8gMiwgbGVuZ3RoKGF0dF9tb2RlbCkgLSAxKSAqIHNlCiAgICBjaSA8LSBtZWFuKGF0dF9tb2RlbCkgKyBjKC1tYXJnaW5fZXJyb3IsIG1hcmdpbl9lcnJvcikKICAKICAgICMgSW5zZXJ0IHRoZSBhdmVyYWdlIHZhbHVlIGJldHdlZW4gdGhlIHR3byBib3VuZHMKICAgIGNpX3dpdGhfYXZlcmFnZSA8LSBjKGNpWzFdLCBtZWFuKGNpKSwgY2lbMl0pCiAgICAKICAgICMgR2V0IHRoZSBsaXN0IGZyb20gdGhlIGVudmlyb25tZW50CiAgICBjaV9saXN0IDwtIGdldChDSV9wcmVmaXgpCiAgICAKICAgICMgU3RvcmUgdGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgaW4gdGhlIGxpc3QKICAgIGNpX2xpc3RbW3Bhc3RlKCJ0IiwgbiArIGZvcl9saXN0LCBzZXAgPSAiIildXSA8LSBjaV93aXRoX2F2ZXJhZ2UKICAgIAogICAgIyBBc3NpZ24gdGhlIG1vZGlmaWVkIGxpc3QgYmFjayB0byB0aGUgZW52aXJvbm1lbnQKICAgIGFzc2lnbihDSV9wcmVmaXgsIGNpX2xpc3QpCiAgICAKICB9CiAgCiAgcmV0dXJuKGdldChDSV9wcmVmaXgpKSAjIFdlIHdhbnQgdGhpcyBsaXN0IHRvIGJlIHRoZSByZXR1cm4gdmFsdWUKICAKfQpgYGAKCkxldCdzIGdldCBvdXIgY29uZmlkZW5jZSBpbnRlcnZhbHMgcGVyIG1vZGVsCgpJbnB1dHMKYGBge3J9CmNvbmZpZGVuY2VfbGV2ZWwgPC0gMC45NQpzdGF0aXN0aWNfTEFTU08gPC0gQVRUX01DX3Blci5wZXJpb2QuTEFTU08Kc3RhdGlzdGljX1JGIDwtIEFUVF9NQ19wZXIucGVyaW9kLlJGCnN0YXRpc3RpY19YZ0IgPC0gQVRUX01DX3Blci5wZXJpb2QuWGdCCnN0YXRpc3RpY19LZXJuZWxLbm4gPC0gQVRUX01DX3Blci5wZXJpb2QuS2VybmVsS25uCnN0YXRpc3RpY19Kb2ludE0gPC0gQVRUX01DX3Blci5wZXJpb2QuSm9pbnRNCm51bV9wZXJpb2RzIDwtIDMKcGVyaW9kX3RyZWF0bWVudCA8LSAzCmBgYAoKUGVyIE1vZGVsCmBgYHtyfQpDSV9NQ19MQVNTTyA8LSBDb25maWRlbmNlX2ludGVydmFscyhjb25maWRlbmNlX2xldmVsLCBzdGF0aXN0aWNfTEFTU08sIG51bV9wZXJpb2RzLCBwZXJpb2RfdHJlYXRtZW50KQpDSV9NQ19SRiA8LSBDb25maWRlbmNlX2ludGVydmFscyhjb25maWRlbmNlX2xldmVsLCBzdGF0aXN0aWNfUkYsIG51bV9wZXJpb2RzLCBwZXJpb2RfdHJlYXRtZW50KQpDSV9NQ19YZ0IgPC0gQ29uZmlkZW5jZV9pbnRlcnZhbHMoY29uZmlkZW5jZV9sZXZlbCwgc3RhdGlzdGljX1hnQiwgbnVtX3BlcmlvZHMsIHBlcmlvZF90cmVhdG1lbnQpCkNJX01DX0tlcm5lbEtubiA8LSBDb25maWRlbmNlX2ludGVydmFscyhjb25maWRlbmNlX2xldmVsLCBzdGF0aXN0aWNfS2VybmVsS25uLCBudW1fcGVyaW9kcywgcGVyaW9kX3RyZWF0bWVudCkKQ0lfTUNfSm9pbnRNIDwtIENvbmZpZGVuY2VfaW50ZXJ2YWxzKGNvbmZpZGVuY2VfbGV2ZWwsIHN0YXRpc3RpY19Kb2ludE0sIG51bV9wZXJpb2RzLCBwZXJpb2RfdHJlYXRtZW50KQoKQ0lfTUNfTEFTU08uZGYgPC0gYXMuZGF0YS5mcmFtZShDSV9NQ19MQVNTTykKQ0lfTUNfUkYuZGYgPC0gYXMuZGF0YS5mcmFtZShDSV9NQ19SRikKQ0lfTUNfWGdCLmRmIDwtIGFzLmRhdGEuZnJhbWUoQ0lfTUNfWGdCKQpDSV9NQ19LZXJuZWxLbm4uZGYgPC0gYXMuZGF0YS5mcmFtZShDSV9NQ19LZXJuZWxLbm4pCkNJX01DX0pvaW50TS5kZiA8LSBhcy5kYXRhLmZyYW1lKENJX01DX0pvaW50TSkKYGBgCgpHUkFQSFMgQU5EIFRBQkxFUyAKCkxldCdzIGdldCBhIHN1cGVyIG5pY2UgZ3JhcGggdG8gc2hvdyB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbHMKCmBgYHtyfQojIENvbWJpbmUgdGhlIGRhdGEgZnJhbWVzIGludG8gYSBzaW5nbGUgZGF0YSBmcmFtZQphbGxfY2lfZGF0YSA8LSBiaW5kX3Jvd3MoCiAgbXV0YXRlKENJX01DX0xBU1NPLmRmLCBtb2RlbCA9ICJMQVNTTyIpLAogIG11dGF0ZShDSV9NQ19SRi5kZiwgbW9kZWwgPSAiUkYiKSwKICBtdXRhdGUoQ0lfTUNfWGdCLmRmLCBtb2RlbCA9ICJYZ0IiKSwKICBtdXRhdGUoQ0lfTUNfS2VybmVsS25uLmRmLCBtb2RlbCA9ICJLZXJuZWxLbm4iKSwKICBtdXRhdGUoQ0lfTUNfSm9pbnRNLmRmLCBtb2RlbCA9ICJKb2ludE0iKQopCgoKIyBSZXNoYXBlIHRoZSBkYXRhIGZvciBlYXNpZXIgcGxvdHRpbmcKYWxsX2NpX2RhdGFfbG9uZyA8LSBhbGxfY2lfZGF0YSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IHN0YXJ0c193aXRoKCJ0IiksIG5hbWVzX3RvID0gInBlcmlvZCIsIHZhbHVlc190byA9ICJ2YWx1ZXMiKSAlPiUKICBtdXRhdGUobmFtZSA9IGlmZWxzZShncmVwbCgiTG93ZXIiLCBwZXJpb2QpLCAiTG93ZXIiLAogICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShncmVwbCgiQXZlcmFnZSIsIHBlcmlvZCksICJBdmVyYWdlIiwgIlVwcGVyIikpKQoKCiMgUGxvdCB1c2luZyBnZ3Bsb3QyCmdncGxvdChhbGxfY2lfZGF0YV9sb25nLCBhZXMoeCA9IHBlcmlvZCwgeSA9IHZhbHVlcywgY29sb3IgPSBtb2RlbCwgbGluZXR5cGUgPSBuYW1lKSkgKwogIGdlb21fbGluZShzaXplID0gMSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuMykpICsKICBnZW9tX3BvaW50KHNpemUgPSAzLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC4zKSkgKwogIGxhYnModGl0bGUgPSAiIiwKICAgICAgIHggPSAiUGVyaW9kIiwKICAgICAgIHkgPSAiVmFsdWVzIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgc2NhbGVfbGluZXR5cGVfbWFudWFsKHZhbHVlcyA9IGMoIkxvd2VyIiA9ICJkYXNoZWQiLCAiQXZlcmFnZSIgPSAic29saWQiLCAiVXBwZXIiID0gImRhc2hlZCIpKQoKIyBEZWZpbmUgdGhlIHBhdGggZm9yIHRoZSBQTkcgaW1hZ2UKTUxfTUNfQ0kgPC0gIi9Vc2Vycy9ib25qb3VyL0RvY3VtZW50cy9NYXN0ZXIgaW4gRWNvbm9taWNzIEJvbm4vNXRoIHNlbWVzdGVyL1RoZXNpcy9SLUNvZGUvRHJhZnRzLzEydGggRHJhZnQvSW1hZ2VzIE1vbnRlQ2FybG8vTUxfTUNfQ0kucG5nIgoKIyBTYXZlIHRoZSBnZ3Bsb3QgYXMgYSBQTkcgaW1hZ2UKZ2dzYXZlKGZpbGVuYW1lID0gTUxfTUNfQ0ksIHBsb3QgPSBsYXN0X3Bsb3QoKSwgd2lkdGggPSA2LCBoZWlnaHQgPSA0LCBkcGkgPSAzMDApCgpgYGAKTGV0J3MgcmVjb3ZlciB0aGUgYXZlcmFnZSBsZW5ndGggb2YgdGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGFuZCB0aGUgdGltZXMgbXkgQVRUIGZhbGxzIGluc2lkZQpgYGB7cn0KIyBMZXQncyBjaGVjayB0aGUgYXZlcmFnZSBsZW5ndGggb2YgdGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGFib3ZlIGFuZCB0aGUgdGltZXMgdGhlIEFUVCBhY3R1YWxseSBmYWxscyB3aXRoaW4gdGhvc2UgQ0kKCiMgZm9yIGJvdGgKbW9kZWxzIDwtIGMoIkxBU1NPIiwgIlJGIiwgIlhnQiIsICJLZXJuZWxLbm4iLCAiSm9pbnRNIikKCiMgZm9yIHRoZSBjb25maWRlbmNlIGludGVydmFscyBsZW5ndGgKQ0lfTUNfbGVuZ3RoX2xpc3QgPC0gbWF0cml4KE5BLCBucm93ID0gbGVuZ3RoKG1vZGVscyksIG5jb2wgPSBlbmRpbmdfdGVzdF9wZXJpb2QgLSAyKQoKIyBmb3IgdGhlIGNvdW50ZXIgdGhhdCB3aWxsIGJyaW5nIG1lIHRoZSB0aW1lcyBpdCBhY3R1YWxseSBmYWxscyBpbnNpZGUgdGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWwKQ0lfTUNfVGltZXNfZmFsbF9pbnNpZGVfbGlzdCA8LSBtYXRyaXgoTkEsIG5yb3cgPSBsZW5ndGgobW9kZWxzKSwgbmNvbCA9IGVuZGluZ190ZXN0X3BlcmlvZCAtIDIpCgpmb3IgKG1vZGVsIGluIG1vZGVscykgewogIAogICMgZm9yIHRoZSBjb25maWRlbmNlIGludGVydmFscyBsZW5ndGgKICBDSV9NQ19sZW5ndGggPC0gbWF0cml4KE5BLCBucm93ID0gMSwgbmNvbCA9IGVuZGluZ190ZXN0X3BlcmlvZCAtIDIpCiAgCiAgIyBmb3IgdGhlIGNvdW50ZXIgdGhhdCB3aWxsIGJyaW5nIG1lIHRoZSB0aW1lcyBpdCBhY3R1YWxseSBmYWxscyBpbnNpZGUgdGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWwKICBDSV9UaW1lc19mYWxsX2luc2lkZSA8LSBtYXRyaXgoTkEsIG5yb3cgPSAxLCBuY29sID0gZW5kaW5nX3Rlc3RfcGVyaW9kIC0gMikKICAKICBmb3IgKGkgaW4gcGVyaW9kX3RyZWF0bWVudDplbmRpbmdfdGVzdF9wZXJpb2QpIHsKICAgIAogICAgIyBmb3IgdGhlIGxlbmd0aCBvZiB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbHMgbGVuZ3RoCiAgICBkZiA8LSBnZXQocGFzdGUoIkNJX01DXyIsIG1vZGVsLCAiLmRmIiwgc2VwID0gIiIpKQogICAgCiAgICBDSV9NQ19sZW5ndGhbMSwgaSAtIDJdIDwtIGRmWzMsIGkgLSAyXSAtIGRmWzEsIGkgLSAyXQogICAgCiAgICAjIGZvciB0aGUgY291bnRlciB0aGF0IHdpbGwgYnJpbmcgbWUgdGhlIHRpbWVzIGl0IGFjdHVhbGx5IGZhbGxzIGluc2lkZSB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbAogICAgY291bnRlcl9BVFRfTUxfTUMgPC0gMAogICAgCiAgICBmb3IgKGogaW4gMTpudW1fc2ltdWxhdGlvbnMpIHsKICAgICAgCiAgICAgICMgZm9yIHRoZSBjb3VudGVyIHRoYXQgd2lsbCBicmluZyBtZSB0aGUgdGltZXMgaXQgYWN0dWFsbHkgZmFsbHMgaW5zaWRlIHRoZSBjb25maWRlbmNlIGludGVydmFsCiAgICAgIGNvdW50ZXIgPC0gZ2V0KHBhc3RlKCJBVFRfTUNfcGVyLnBlcmlvZC4iLCBtb2RlbCwgc2VwID0gIiIpKQogICAgICAKICAgICAgIyBpZiBpdCBmYWxscywgYWRkIG9uZQogICAgICBpZihkZlsxLCBpIC0gMl0gPCBjb3VudGVyW2osIGkgLSAyXSAmIGNvdW50ZXJbaiwgaSAtIDJdIDwgZGZbMywgaSAtIDJdKXsKICAgICAgICAKICAgICAgICBjb3VudGVyX0FUVF9NTF9NQyA9IGNvdW50ZXJfQVRUX01MX01DICsgMQogICAgICAgIAogICAgICB9IGVsc2UgewogIAogICAgICAgIGNvdW50ZXJfQVRUX01MX01DID0gY291bnRlcl9BVFRfTUxfTUMgKyAwCiAgICAgICAgCiAgICAgIH0KICAgICAgCiAgICB9CiAgICAKICAgIENJX1RpbWVzX2ZhbGxfaW5zaWRlWzEsIGkgLSAyXSA8LSBjb3VudGVyX0FUVF9NTF9NQwogICAgCiAgfQogIAogICMgZm9yIHRoZSBjb25maWRlbmNlIGludGVydmFscyBsZW5ndGgKICBDSV9NQ19sZW5ndGhfbGlzdFttYXRjaChtb2RlbCwgbW9kZWxzKSxdIDwtIENJX01DX2xlbmd0aAogIAogICMgZm9yIHRoZSBjb3VudGVyIHRoYXQgd2lsbCBicmluZyBtZSB0aGUgdGltZXMgaXQgYWN0dWFsbHkgZmFsbHMgaW5zaWRlIHRoZSBjb25maWRlbmNlIGludGVydmFsCiAgQ0lfTUNfVGltZXNfZmFsbF9pbnNpZGVfbGlzdFttYXRjaChtb2RlbCwgbW9kZWxzKSxdIDwtIENJX1RpbWVzX2ZhbGxfaW5zaWRlCn0KYGBgCgpUQUJMRVMKCkxlbmd0aCBvZiB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbHMgdGFibGUKYGBge3J9CiMgVHJhbnNmb3JtIGl0IGludG8gYSBkYXRhZnJhbWUKQ0lfTUNfbGVuZ3RoLmRmIDwtIGFzLmRhdGEuZnJhbWUoQ0lfTUNfbGVuZ3RoX2xpc3QpCgojIEF2ZXJhZ2VzCkF2ZXJhZ2VzLkNJX01DX2xlbmd0aC5kZiA8LSByb3dNZWFucyhDSV9NQ19sZW5ndGguZGYpCgojIFRhYmxlClRhYmxlX0NJX01DX2xlbmd0aC5kZiA8LSBjYmluZChDSV9NQ19sZW5ndGguZGYsIEF2ZXJhZ2VzLkNJX01DX2xlbmd0aC5kZikKCiMgQWRkIGNvbHVtbiBuYW1lcwpjb2xuYW1lcyhUYWJsZV9DSV9NQ19sZW5ndGguZGYpIDwtIGMoInQzIiwgInQ0IiwgInQ1IiwgImF2ZXJhZ2UiKSAKCiMgQWRkIHJvdyBuYW1lcwpyb3duYW1lcyhUYWJsZV9DSV9NQ19sZW5ndGguZGYpIDwtIG1vZGVscwoKIyBDb252ZXJ0IHRoZSBkYXRhIGZyYW1lIHRvIExhVGVYIGZvcm1hdCB1c2luZyB4dGFibGUKbGF0ZXhfQ0lfTUNfbGVuZ3RoLmRmIDwtIHh0YWJsZShUYWJsZV9DSV9NQ19sZW5ndGguZGYpCgojIFByaW50IHRoZSBMYVRlWCBjb2RlCnByaW50KGxhdGV4X0NJX01DX2xlbmd0aC5kZikKYGBgCgpOdW1iZXIgb2YgdGltZXMgaXQgZmFsbHMgaW5zaWRlIHRoZSBDb25maWRlbmNlIEludGVydmFscwpgYGB7cn0KIyBUcmFuc2Zvcm0gaXQgaW50byBhIGRhdGFmcmFtZQpDSV9NQ19UaW1lc19mYWxsX2luc2lkZS5kZiA8LSBhcy5kYXRhLmZyYW1lKENJX01DX1RpbWVzX2ZhbGxfaW5zaWRlX2xpc3QpCgojIEF2ZXJhZ2VzCkF2ZXJhZ2VzLkNJX01DX1RpbWVzX2ZhbGxfaW5zaWRlLmRmICA8LSByb3dNZWFucyhDSV9NQ19UaW1lc19mYWxsX2luc2lkZS5kZiApCgojIFRhYmxlClRhYmxlX0NJX01DX1RpbWVzX2ZhbGxfaW5zaWRlLmRmICA8LSBjYmluZChDSV9NQ19UaW1lc19mYWxsX2luc2lkZS5kZiAsIEF2ZXJhZ2VzLkNJX01DX1RpbWVzX2ZhbGxfaW5zaWRlLmRmKQoKIyBBZGQgY29sdW1uIG5hbWVzCmNvbG5hbWVzKFRhYmxlX0NJX01DX1RpbWVzX2ZhbGxfaW5zaWRlLmRmKSA8LSBjKCJ0MyIsICJ0NCIsICJ0NSIsICJhdmVyYWdlIikgCgojIEFkZCByb3cgbmFtZXMKcm93bmFtZXMoVGFibGVfQ0lfTUNfVGltZXNfZmFsbF9pbnNpZGUuZGYpIDwtIG1vZGVscwoKIyBDb252ZXJ0IHRoZSBkYXRhIGZyYW1lIHRvIExhVGVYIGZvcm1hdCB1c2luZyB4dGFibGUKbGF0ZXhfQ0lfTUNfVGltZXNfZmFsbF9pbnNpZGUuZGYgPC0geHRhYmxlKFRhYmxlX0NJX01DX1RpbWVzX2ZhbGxfaW5zaWRlLmRmKQoKIyBQcmludCB0aGUgTGFUZVggY29kZQpwcmludChsYXRleF9DSV9NQ19UaW1lc19mYWxsX2luc2lkZS5kZikKYGBgCgojIC0tLS0tLS0gV0FJVCBMRVQnUyBUUlkgVE8gUkVBQ0ggVEhFIDkwIFRJTUVTIFRIQVQgQVQgTEVBU1QgVEhFIEFUVCBPRiBPTkUgTU9ERUwgRkFMTFMgV0lUSElOIFRIRSBDT05GSURFTkNFIElOVEVSVkFMUyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgpQZXIgTW9kZWwKYGBge3J9CkNJX01DX0xBU1NPIDwtIENvbmZpZGVuY2VfaW50ZXJ2YWxzKGNvbmZpZGVuY2VfbGV2ZWwsIHN0YXRpc3RpY19MQVNTTywgbnVtX3BlcmlvZHMsIHBlcmlvZF90cmVhdG1lbnQpCkNJX01DX1JGIDwtIENvbmZpZGVuY2VfaW50ZXJ2YWxzKGNvbmZpZGVuY2VfbGV2ZWwsIHN0YXRpc3RpY19SRiwgbnVtX3BlcmlvZHMsIHBlcmlvZF90cmVhdG1lbnQpCkNJX01DX1hnQiA8LSBDb25maWRlbmNlX2ludGVydmFscyhjb25maWRlbmNlX2xldmVsLCBzdGF0aXN0aWNfWGdCLCBudW1fcGVyaW9kcywgcGVyaW9kX3RyZWF0bWVudCkKQ0lfTUNfS2VybmVsS25uIDwtIENvbmZpZGVuY2VfaW50ZXJ2YWxzKGNvbmZpZGVuY2VfbGV2ZWwsIHN0YXRpc3RpY19LZXJuZWxLbm4sIG51bV9wZXJpb2RzLCBwZXJpb2RfdHJlYXRtZW50KQpDSV9NQ19Kb2ludE0gPC0gQ29uZmlkZW5jZV9pbnRlcnZhbHMoY29uZmlkZW5jZV9sZXZlbCwgc3RhdGlzdGljX0pvaW50TSwgbnVtX3BlcmlvZHMsIHBlcmlvZF90cmVhdG1lbnQpCgpDSV9NQ19MQVNTTy5kZiA8LSBhcy5kYXRhLmZyYW1lKENJX01DX0xBU1NPKQpDSV9NQ19SRi5kZiA8LSBhcy5kYXRhLmZyYW1lKENJX01DX1JGKQpDSV9NQ19YZ0IuZGYgPC0gYXMuZGF0YS5mcmFtZShDSV9NQ19YZ0IpCkNJX01DX0tlcm5lbEtubi5kZiA8LSBhcy5kYXRhLmZyYW1lKENJX01DX0tlcm5lbEtubikKQ0lfTUNfSm9pbnRNLmRmIDwtIGFzLmRhdGEuZnJhbWUoQ0lfTUNfSm9pbnRNKQpgYGAKCkxldCdzIHJlY292ZXIgdGhlIGF2ZXJhZ2UgbGVuZ3RoIG9mIHRoZSBjb25maWRlbmNlIGludGVydmFscyBhbmQgdGhlIHRpbWVzIG15IEFUVCBmYWxscyBpbnNpZGUKCldoYXQgYWJvdXQgYSBzdGFnZ2VyZWQgYWRvcHRpb24gdG8gYWNjb3VudCBmb3IgdGhlIGZhY3QgdGhhdCBDSSBpbmNyZWFzZSBpbiBsZW5ndGggCmBgYHtyfQojIExldCdzIGNoZWNrIHRoZSBhdmVyYWdlIGxlbmd0aCBvZiB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbHMgYWJvdmUgYW5kIHRoZSB0aW1lcyB0aGUgQVRUIGFjdHVhbGx5IGZhbGxzIHdpdGhpbiB0aG9zZSBDSQoKIyBmb3IgYm90aAptb2RlbHMgPC0gYygiTEFTU08iLCAiUkYiLCAiWGdCIiwgIktlcm5lbEtubiIsICJKb2ludE0iKQoKIyBmb3IgdGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGxlbmd0aApDSV9NQ19sZW5ndGhfbGlzdCA8LSBtYXRyaXgoTkEsIG5yb3cgPSBsZW5ndGgobW9kZWxzKSwgbmNvbCA9IGVuZGluZ190ZXN0X3BlcmlvZCAtIDIpCgojIGZvciB0aGUgY291bnRlciB0aGF0IHdpbGwgYnJpbmcgbWUgdGhlIHRpbWVzIGl0IGFjdHVhbGx5IGZhbGxzIGluc2lkZSB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbApDSV9NQ19UaW1lc19mYWxsX2luc2lkZV9saXN0IDwtIG1hdHJpeChOQSwgbnJvdyA9IGxlbmd0aChtb2RlbHMpLCBuY29sID0gZW5kaW5nX3Rlc3RfcGVyaW9kIC0gMikKCmZvciAobW9kZWwgaW4gbW9kZWxzKSB7CiAgCiAgIyBmb3IgdGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGxlbmd0aAogIENJX01DX2xlbmd0aCA8LSBtYXRyaXgoTkEsIG5yb3cgPSAxLCBuY29sID0gZW5kaW5nX3Rlc3RfcGVyaW9kIC0gMikKICAKICAjIGZvciB0aGUgY291bnRlciB0aGF0IHdpbGwgYnJpbmcgbWUgdGhlIHRpbWVzIGl0IGFjdHVhbGx5IGZhbGxzIGluc2lkZSB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbAogIENJX1RpbWVzX2ZhbGxfaW5zaWRlIDwtIG1hdHJpeChOQSwgbnJvdyA9IDEsIG5jb2wgPSBlbmRpbmdfdGVzdF9wZXJpb2QgLSAyKQogIAogIGZvciAoaSBpbiBwZXJpb2RfdHJlYXRtZW50OmVuZGluZ190ZXN0X3BlcmlvZCkgewogICAgCiAgICAjIGZvciB0aGUgbGVuZ3RoIG9mIHRoZSBjb25maWRlbmNlIGludGVydmFscyBsZW5ndGgKICAgIGRmIDwtIGdldChwYXN0ZSgiQ0lfTUNfIiwgbW9kZWwsICIuZGYiLCBzZXAgPSAiIikpCiAgICAKICAgICMgVGVtcG9yYXJlbHkgc2F2aW5nIHRoZSB2YWx1ZXMgb2YgdGhlIHVwcGVyIGFuZCBsb3dlciBjb25maWRlbmNlIGludGVydmFscwogICAgaWYoaSA9PSBwZXJpb2RfdHJlYXRtZW50KXsKICAgICAgdWNpX3RlbXBvIDwtIGRmWzMsIGkgLSAyXSArIDAuMgogICAgICBsY2lfdGVtcG8gPC0gZGZbMSwgaSAtIDJdIC0gMC4yCiAgICB9ZWxzZSBpZihpID09IHBlcmlvZF90cmVhdG1lbnQgKyAxKXsKICAgICAgdWNpX3RlbXBvIDwtIGRmWzMsIGkgLSAyXSArIDAuMzUKICAgICAgbGNpX3RlbXBvIDwtIGRmWzEsIGkgLSAyXSAtIDAuMzUKICAgIH1lbHNlewogICAgICB1Y2lfdGVtcG8gPC0gZGZbMywgaSAtIDJdICsgMC41CiAgICAgIGxjaV90ZW1wbyA8LSBkZlsxLCBpIC0gMl0gLSAwLjUKICAgIH0KICAgIAogICAgQ0lfTUNfbGVuZ3RoWzEsIGkgLSAyXSA8LSB1Y2lfdGVtcG8gLSBsY2lfdGVtcG8gIyB1cHBlciBtaW51cyBsb3dlciBib3VuZAogICAgCiAgICAjIGZvciB0aGUgY291bnRlciB0aGF0IHdpbGwgYnJpbmcgbWUgdGhlIHRpbWVzIGl0IGFjdHVhbGx5IGZhbGxzIGluc2lkZSB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbAogICAgY291bnRlcl9BVFRfTUxfTUMgPC0gMAogICAgCiAgICBmb3IgKGogaW4gMTpudW1fc2ltdWxhdGlvbnMpIHsKICAgICAgCiAgICAgICMgZm9yIHRoZSBjb3VudGVyIHRoYXQgd2lsbCBicmluZyBtZSB0aGUgdGltZXMgaXQgYWN0dWFsbHkgZmFsbHMgaW5zaWRlIHRoZSBjb25maWRlbmNlIGludGVydmFsCiAgICAgIGNvdW50ZXIgPC0gZ2V0KHBhc3RlKCJBVFRfTUNfcGVyLnBlcmlvZC4iLCBtb2RlbCwgc2VwID0gIiIpKQogICAgICAKICAgICAgIyBpZiBpdCBmYWxscywgYWRkIG9uZQogICAgICBpZihsY2lfdGVtcG8gPCBjb3VudGVyW2osIGkgLSAyXSAmIGNvdW50ZXJbaiwgaSAtIDJdIDwgdWNpX3RlbXBvKXsKICAgICAgICAKICAgICAgICBjb3VudGVyX0FUVF9NTF9NQyA9IGNvdW50ZXJfQVRUX01MX01DICsgMQogICAgICAgIAogICAgICB9IGVsc2UgewogIAogICAgICAgIGNvdW50ZXJfQVRUX01MX01DID0gY291bnRlcl9BVFRfTUxfTUMgKyAwCiAgICAgICAgCiAgICAgIH0KICAgICAgCiAgICB9CiAgICAKICAgIENJX1RpbWVzX2ZhbGxfaW5zaWRlWzEsIGkgLSAyXSA8LSBjb3VudGVyX0FUVF9NTF9NQwogICAgCiAgfQogIAogICMgZm9yIHRoZSBjb25maWRlbmNlIGludGVydmFscyBsZW5ndGgKICBDSV9NQ19sZW5ndGhfbGlzdFttYXRjaChtb2RlbCwgbW9kZWxzKSxdIDwtIENJX01DX2xlbmd0aAogIAogICMgZm9yIHRoZSBjb3VudGVyIHRoYXQgd2lsbCBicmluZyBtZSB0aGUgdGltZXMgaXQgYWN0dWFsbHkgZmFsbHMgaW5zaWRlIHRoZSBjb25maWRlbmNlIGludGVydmFsCiAgQ0lfTUNfVGltZXNfZmFsbF9pbnNpZGVfbGlzdFttYXRjaChtb2RlbCwgbW9kZWxzKSxdIDwtIENJX1RpbWVzX2ZhbGxfaW5zaWRlCn0KYGBgCgoKVEFCTEVTCgpMZW5ndGggb2YgdGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIHRhYmxlCmBgYHtyfQojIFRyYW5zZm9ybSBpdCBpbnRvIGEgZGF0YWZyYW1lCkNJX01DX2xlbmd0aC5kZiA8LSBhcy5kYXRhLmZyYW1lKENJX01DX2xlbmd0aF9saXN0KQoKIyBBdmVyYWdlcwpBdmVyYWdlcy5DSV9NQ19sZW5ndGguZGYgPC0gcm93TWVhbnMoQ0lfTUNfbGVuZ3RoLmRmKQoKIyBUYWJsZQpUYWJsZV9DSV9NQ19sZW5ndGguZGYgPC0gY2JpbmQoQ0lfTUNfbGVuZ3RoLmRmLCBBdmVyYWdlcy5DSV9NQ19sZW5ndGguZGYpCgojIEFkZCBjb2x1bW4gbmFtZXMKY29sbmFtZXMoVGFibGVfQ0lfTUNfbGVuZ3RoLmRmKSA8LSBjKCJ0MyIsICJ0NCIsICJ0NSIsICJhdmVyYWdlIikgCgojIEFkZCByb3cgbmFtZXMKcm93bmFtZXMoVGFibGVfQ0lfTUNfbGVuZ3RoLmRmKSA8LSBtb2RlbHMKCiMgQ29udmVydCB0aGUgZGF0YSBmcmFtZSB0byBMYVRlWCBmb3JtYXQgdXNpbmcgeHRhYmxlCmxhdGV4X0NJX01DX2xlbmd0aC5kZiA8LSB4dGFibGUoVGFibGVfQ0lfTUNfbGVuZ3RoLmRmKQoKIyBQcmludCB0aGUgTGFUZVggY29kZQpwcmludChsYXRleF9DSV9NQ19sZW5ndGguZGYpCmBgYAoKTnVtYmVyIG9mIHRpbWVzIGl0IGZhbGxzIGluc2lkZSB0aGUgQ29uZmlkZW5jZSBJbnRlcnZhbHMKYGBge3J9CiMgVHJhbnNmb3JtIGl0IGludG8gYSBkYXRhZnJhbWUKQ0lfTUNfVGltZXNfZmFsbF9pbnNpZGUuZGYgPC0gYXMuZGF0YS5mcmFtZShDSV9NQ19UaW1lc19mYWxsX2luc2lkZV9saXN0KQoKIyBBdmVyYWdlcwpBdmVyYWdlcy5DSV9NQ19UaW1lc19mYWxsX2luc2lkZS5kZiAgPC0gcm93TWVhbnMoQ0lfTUNfVGltZXNfZmFsbF9pbnNpZGUuZGYgKQoKIyBUYWJsZQpUYWJsZV9DSV9NQ19UaW1lc19mYWxsX2luc2lkZS5kZiAgPC0gY2JpbmQoQ0lfTUNfVGltZXNfZmFsbF9pbnNpZGUuZGYgLCBBdmVyYWdlcy5DSV9NQ19UaW1lc19mYWxsX2luc2lkZS5kZikKCiMgQWRkIGNvbHVtbiBuYW1lcwpjb2xuYW1lcyhUYWJsZV9DSV9NQ19UaW1lc19mYWxsX2luc2lkZS5kZikgPC0gYygidDMiLCAidDQiLCAidDUiLCAiYXZlcmFnZSIpIAoKIyBBZGQgcm93IG5hbWVzCnJvd25hbWVzKFRhYmxlX0NJX01DX1RpbWVzX2ZhbGxfaW5zaWRlLmRmKSA8LSBtb2RlbHMKCiMgQ29udmVydCB0aGUgZGF0YSBmcmFtZSB0byBMYVRlWCBmb3JtYXQgdXNpbmcgeHRhYmxlCmxhdGV4X0NJX01DX1RpbWVzX2ZhbGxfaW5zaWRlLmRmIDwtIHh0YWJsZShUYWJsZV9DSV9NQ19UaW1lc19mYWxsX2luc2lkZS5kZikKCiMgUHJpbnQgdGhlIExhVGVYIGNvZGUKcHJpbnQobGF0ZXhfQ0lfTUNfVGltZXNfZmFsbF9pbnNpZGUuZGYpCmBgYAoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCkFUVApgYGB7cn0KIyBDcmVhdGUgYSBkYXRhIGZyYW1lCmRmX0FUVCA8LSBkYXRhLmZyYW1lKHggPSAxOmxlbmd0aChNQ19wZXJfc3RhdGlzdGljJEFUVCRMQVNTTyksIHZhbHVlID0gYyhNQ19wZXJfc3RhdGlzdGljJEFUVCRMQVNTTywgTUNfcGVyX3N0YXRpc3RpYyRBVFQkUkYsIE1DX3Blcl9zdGF0aXN0aWMkQVRUJFhnQiwgTUNfcGVyX3N0YXRpc3RpYyRBVFQkS2VybmVsS25uLCBNQ19wZXJfc3RhdGlzdGljJEFUVCRKb2ludE0pLCBncm91cCA9IHJlcChtb2RlbHNfdXAsIGVhY2ggPSBsZW5ndGgoTUNfcGVyX3N0YXRpc3RpYyRBVFQkTEFTU08pKSkKCiMgQ2FsY3VsYXRlIG1lYW4gdmFsdWVzIGZvciB4IGFuZCB5Cm1lYW5fdmFsdWVzX0FUVCA8LSBhZ2dyZWdhdGUodmFsdWUgfiBncm91cCwgZGF0YSA9IGRmX0FUVCwgbWVhbikKbWF4X3ZhbHVlc19BVFQgPC0gYWdncmVnYXRlKHZhbHVlIH4gZ3JvdXAsIGRhdGEgPSBkZl9BVFQsIG1heCkKbWluX3ZhbHVlc19BVFQgPC0gYWdncmVnYXRlKHZhbHVlIH4gZ3JvdXAsIGRhdGEgPSBkZl9BVFQsIG1pbikKdmFyaWFuY2VzX0FUVCA8LSBhZ2dyZWdhdGUodmFsdWUgfiBncm91cCwgZGF0YSA9IGRmX0FUVCwgdmFyKQoKIyBDcmVhdGUgYSBsaW5lIHBsb3QKZ2dwbG90KGRmX0FUVCwgYWVzKHggPSB4LCB5ID0gdmFsdWUsIGNvbG9yID0gZ3JvdXAsIGdyb3VwID0gZ3JvdXApKSArCiAgZ2VvbV9saW5lKCkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9obGluZShkYXRhID0gbWF4X3ZhbHVlc19BVFQsIGFlcyh5aW50ZXJjZXB0ID0gdmFsdWUsIGNvbG9yID0gZ3JvdXAsIGxpbmV0eXBlID0gImRhc2hlZCIpLCBzaXplID0gMS4wKSArCiAgZ2VvbV9obGluZShkYXRhID0gbWluX3ZhbHVlc19BVFQsIGFlcyh5aW50ZXJjZXB0ID0gdmFsdWUsIGNvbG9yID0gZ3JvdXAsIGxpbmV0eXBlID0gImRhc2hlZCIpLCBzaXplID0gMS4wKSArCiAgbGFicyh0aXRsZSA9ICIiLAogICAgICAgeCA9ICJTZWVkIiwKICAgICAgIHkgPSAiQVRUIiwKICAgICAgIGNvbG9yID0gIkdyb3VwIikgKwogIHRoZW1lX21pbmltYWwoKQoKIyBEZWZpbmUgdGhlIHBhdGggZm9yIHRoZSBQTkcgaW1hZ2UKTUNfTUxfQVRUIDwtICIvVXNlcnMvYm9uam91ci9Eb2N1bWVudHMvTWFzdGVyIGluIEVjb25vbWljcyBCb25uLzV0aCBzZW1lc3Rlci9UaGVzaXMvUi1Db2RlL0RyYWZ0cy8xMXRoIERyYWZ0IC0gQWR2YW5jZWQgZnVuY3Rpb24gYW5kIE1vbnRlY2FybG8vSW1hZ2VzIE1vbnRlY2FybG8vTUNfTUxfQVRULnBuZyIKCiMgU2F2ZSB0aGUgZ2dwbG90IGFzIGEgUE5HIGltYWdlCmdnc2F2ZShmaWxlbmFtZSA9IE1DX01MX0FUVCwgcGxvdCA9IGxhc3RfcGxvdCgpLCB3aWR0aCA9IDYsIGhlaWdodCA9IDQsIGRwaSA9IDMwMCkKCmBgYAoKCmBgYHtyfQojIE1lcmdlIHRoZSBkYXRhIGZyYW1lcyBiYXNlZCBvbiB0aGUgJ2dyb3VwJyBjb2x1bW4KcmVzdWx0X0FUVCA8LSBtZXJnZShtZWFuX3ZhbHVlc19BVFQsIG1heF92YWx1ZXNfQVRULCBieSA9ICJncm91cCIsIHN1ZmZpeGVzID0gYygiX21lYW4iLCAiX21heCIpKQpyZXN1bHRfQVRUIDwtIG1lcmdlKHJlc3VsdF9BVFQsIG1pbl92YWx1ZXNfQVRULCBieSA9ICJncm91cCIsIHN1ZmZpeGVzID0gYygiIiwgIl9taW4iKSkKcmVzdWx0X0FUVCA8LSBtZXJnZShyZXN1bHRfQVRULCBtaW5fdmFsdWVzX0FUVCwgYnkgPSAiZ3JvdXAiLCBzdWZmaXhlcyA9IGMoIiIsICJfbWluIikpCnJlc3VsdF9BVFQgPC0gbWVyZ2UocmVzdWx0X0FUVCwgdmFyaWFuY2VzX0FUVCwgYnkgPSAiZ3JvdXAiLCBzdWZmaXhlcyA9IGMoIiIsICJfdmFyIikpCgojIEFzc3VtaW5nIHlvdSBoYXZlIHRoZSAndmFsdWUnIGNvbHVtbiBpbiB5b3VyIGRhdGEgZnJhbWUgJ3Jlc3VsdCcKcmVzdWx0X0FUVCA8LSByZXN1bHRfQVRUWywgIShuYW1lcyhyZXN1bHRfQVRUKSAlaW4lICJ2YWx1ZSIpXQoKIyBDb252ZXJ0IHRoZSBkYXRhIGZyYW1lIHRvIExhVGVYIGZvcm1hdCB1c2luZyB4dGFibGUKbGF0ZXhfY29kZV9BVFQgPC0geHRhYmxlKHJlc3VsdF9BVFQpCgojIFByaW50IHRoZSBMYVRlWCBjb2RlCnByaW50KGxhdGV4X2NvZGVfQVRUKQpgYGAKCgpNQUUKYGBge3J9CiMgQ3JlYXRlIGEgZGF0YSBmcmFtZQpkZl9NQUUgPC0gZGF0YS5mcmFtZSh4ID0gMTpsZW5ndGgoTUNfcGVyX3N0YXRpc3RpYyRNQUUkTEFTU08pLCB2YWx1ZSA9IGMoTUNfcGVyX3N0YXRpc3RpYyRNQUUkTEFTU08sIE1DX3Blcl9zdGF0aXN0aWMkTUFFJFJGLCBNQ19wZXJfc3RhdGlzdGljJE1BRSRYZ0IsIE1DX3Blcl9zdGF0aXN0aWMkTUFFJEtlcm5lbEtubiwgTUNfcGVyX3N0YXRpc3RpYyRNQUUkSm9pbnRNKSwgZ3JvdXAgPSByZXAobW9kZWxzX3VwLCBlYWNoID0gbGVuZ3RoKE1DX3Blcl9zdGF0aXN0aWMkTUFFJExBU1NPKSkpCgojIENhbGN1bGF0ZSBtZWFuIHZhbHVlcyBmb3IgeCBhbmQgeQptZWFuX3ZhbHVlc19NQUUgPC0gYWdncmVnYXRlKHZhbHVlIH4gZ3JvdXAsIGRhdGEgPSBkZl9NQUUsIG1lYW4pCm1heF92YWx1ZXNfTUFFIDwtIGFnZ3JlZ2F0ZSh2YWx1ZSB+IGdyb3VwLCBkYXRhID0gZGZfTUFFLCBtYXgpCm1pbl92YWx1ZXNfTUFFIDwtIGFnZ3JlZ2F0ZSh2YWx1ZSB+IGdyb3VwLCBkYXRhID0gZGZfTUFFLCBtaW4pCnZhcmlhbmNlc19NQUUgPC0gYWdncmVnYXRlKHZhbHVlIH4gZ3JvdXAsIGRhdGEgPSBkZl9NQUUsIHZhcikKCiMgQ3JlYXRlIGEgbGluZSBwbG90CmdncGxvdChkZl9NQUUsIGFlcyh4ID0geCwgeSA9IHZhbHVlLCBjb2xvciA9IGdyb3VwLCBncm91cCA9IGdyb3VwKSkgKwogIGdlb21fbGluZSgpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21faGxpbmUoZGF0YSA9IG1heF92YWx1ZXNfTUFFLCBhZXMoeWludGVyY2VwdCA9IHZhbHVlLCBjb2xvciA9IGdyb3VwLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSwgc2l6ZSA9IDEuMCkgKwogIGdlb21faGxpbmUoZGF0YSA9IG1pbl92YWx1ZXNfTUFFLCBhZXMoeWludGVyY2VwdCA9IHZhbHVlLCBjb2xvciA9IGdyb3VwLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSwgc2l6ZSA9IDEuMCkgKwogIGxhYnModGl0bGUgPSAiIiwKICAgICAgIHggPSAiU2VlZCIsCiAgICAgICB5ID0gIk1BRSIsCiAgICAgICBjb2xvciA9ICJHcm91cCIpICsKICB0aGVtZV9taW5pbWFsKCkKCiMgRGVmaW5lIHRoZSBwYXRoIGZvciB0aGUgUE5HIGltYWdlCk1DX01MX01BRSA8LSAiL1VzZXJzL2JvbmpvdXIvRG9jdW1lbnRzL01hc3RlciBpbiBFY29ub21pY3MgQm9ubi81dGggc2VtZXN0ZXIvVGhlc2lzL1ItQ29kZS9EcmFmdHMvMTF0aCBEcmFmdCAtIEFkdmFuY2VkIGZ1bmN0aW9uIGFuZCBNb250ZWNhcmxvL0ltYWdlcyBNb250ZWNhcmxvL01DX01MX01BRS5wbmciCgojIFNhdmUgdGhlIGdncGxvdCBhcyBhIFBORyBpbWFnZQpnZ3NhdmUoZmlsZW5hbWUgPSBNQ19NTF9NQUUsIHBsb3QgPSBsYXN0X3Bsb3QoKSwgd2lkdGggPSA2LCBoZWlnaHQgPSA0LCBkcGkgPSAzMDApCgpgYGAKCmBgYHtyfQojIE1lcmdlIHRoZSBkYXRhIGZyYW1lcyBiYXNlZCBvbiB0aGUgJ2dyb3VwJyBjb2x1bW4KcmVzdWx0X01BRSA8LSBtZXJnZShtZWFuX3ZhbHVlc19NQUUsIG1heF92YWx1ZXNfTUFFLCBieSA9ICJncm91cCIsIHN1ZmZpeGVzID0gYygiX21lYW4iLCAiX21heCIpKQpyZXN1bHRfTUFFIDwtIG1lcmdlKHJlc3VsdF9NQUUsIG1pbl92YWx1ZXNfTUFFLCBieSA9ICJncm91cCIsIHN1ZmZpeGVzID0gYygiIiwgIl9taW4iKSkKcmVzdWx0X01BRSA8LSBtZXJnZShyZXN1bHRfTUFFLCBtaW5fdmFsdWVzX01BRSwgYnkgPSAiZ3JvdXAiLCBzdWZmaXhlcyA9IGMoIiIsICJfbWluIikpCnJlc3VsdF9NQUUgPC0gbWVyZ2UocmVzdWx0X01BRSwgdmFyaWFuY2VzX01BRSwgYnkgPSAiZ3JvdXAiLCBzdWZmaXhlcyA9IGMoIiIsICJfdmFyIikpCgojIEFzc3VtaW5nIHlvdSBoYXZlIHRoZSAndmFsdWUnIGNvbHVtbiBpbiB5b3VyIGRhdGEgZnJhbWUgJ3Jlc3VsdCcKcmVzdWx0X01BRSA8LSByZXN1bHRfTUFFWywgIShuYW1lcyhyZXN1bHRfTUFFKSAlaW4lICJ2YWx1ZSIpXQoKIyBDb252ZXJ0IHRoZSBkYXRhIGZyYW1lIHRvIExhVGVYIGZvcm1hdCB1c2luZyB4dGFibGUKbGF0ZXhfY29kZV9NQUUgPC0geHRhYmxlKHJlc3VsdF9NQUUpCgojIFByaW50IHRoZSBMYVRlWCBjb2RlCnByaW50KGxhdGV4X2NvZGVfTUFFKQpgYGAKCgpNU0UKYGBge3J9CiMgQ3JlYXRlIGEgZGF0YSBmcmFtZQpkZl9NU0UgPC0gZGF0YS5mcmFtZSh4ID0gMTpsZW5ndGgoTUNfcGVyX3N0YXRpc3RpYyRNU0UkTEFTU08pLCB2YWx1ZSA9IGMoTUNfcGVyX3N0YXRpc3RpYyRNU0UkTEFTU08sIE1DX3Blcl9zdGF0aXN0aWMkTVNFJFJGLCBNQ19wZXJfc3RhdGlzdGljJE1TRSRYZ0IsIE1DX3Blcl9zdGF0aXN0aWMkTVNFJEtlcm5lbEtubiwgTUNfcGVyX3N0YXRpc3RpYyRNU0UkSm9pbnRNKSwgZ3JvdXAgPSByZXAobW9kZWxzX3VwLCBlYWNoID0gbGVuZ3RoKE1DX3Blcl9zdGF0aXN0aWMkTVNFJExBU1NPKSkpCgojIENhbGN1bGF0ZSBtZWFuIHZhbHVlcyBmb3IgeCBhbmQgeQptZWFuX3ZhbHVlc19NU0UgPC0gYWdncmVnYXRlKHZhbHVlIH4gZ3JvdXAsIGRhdGEgPSBkZl9NU0UsIG1lYW4pCm1heF92YWx1ZXNfTVNFIDwtIGFnZ3JlZ2F0ZSh2YWx1ZSB+IGdyb3VwLCBkYXRhID0gZGZfTVNFLCBtYXgpCm1pbl92YWx1ZXNfTVNFIDwtIGFnZ3JlZ2F0ZSh2YWx1ZSB+IGdyb3VwLCBkYXRhID0gZGZfTVNFLCBtaW4pCnZhcmlhbmNlc19NU0UgPC0gYWdncmVnYXRlKHZhbHVlIH4gZ3JvdXAsIGRhdGEgPSBkZl9NU0UsIHZhcikKCiMgQ3JlYXRlIGEgbGluZSBwbG90CmdncGxvdChkZl9NU0UsIGFlcyh4ID0geCwgeSA9IHZhbHVlLCBjb2xvciA9IGdyb3VwLCBncm91cCA9IGdyb3VwKSkgKwogIGdlb21fbGluZSgpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21faGxpbmUoZGF0YSA9IG1heF92YWx1ZXNfTVNFLCBhZXMoeWludGVyY2VwdCA9IHZhbHVlLCBjb2xvciA9IGdyb3VwLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSwgc2l6ZSA9IDEuMCkgKwogIGdlb21faGxpbmUoZGF0YSA9IG1pbl92YWx1ZXNfTVNFLCBhZXMoeWludGVyY2VwdCA9IHZhbHVlLCBjb2xvciA9IGdyb3VwLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSwgc2l6ZSA9IDEuMCkgKwogIGxhYnModGl0bGUgPSAiIiwKICAgICAgIHggPSAiU2VlZCIsCiAgICAgICB5ID0gIk1TRSIsCiAgICAgICBjb2xvciA9ICJHcm91cCIpICsKICB0aGVtZV9taW5pbWFsKCkKCiMgRGVmaW5lIHRoZSBwYXRoIGZvciB0aGUgUE5HIGltYWdlCk1DX01MX01TRSA8LSAiL1VzZXJzL2JvbmpvdXIvRG9jdW1lbnRzL01hc3RlciBpbiBFY29ub21pY3MgQm9ubi81dGggc2VtZXN0ZXIvVGhlc2lzL1ItQ29kZS9EcmFmdHMvMTF0aCBEcmFmdCAtIEFkdmFuY2VkIGZ1bmN0aW9uIGFuZCBNb250ZWNhcmxvL0ltYWdlcyBNb250ZWNhcmxvL01DX01MX01TRS5wbmciCgojIFNhdmUgdGhlIGdncGxvdCBhcyBhIFBORyBpbWFnZQpnZ3NhdmUoZmlsZW5hbWUgPSBNQ19NTF9NU0UsIHBsb3QgPSBsYXN0X3Bsb3QoKSwgd2lkdGggPSA2LCBoZWlnaHQgPSA0LCBkcGkgPSAzMDApCgpgYGAKCmBgYHtyfQojIE1lcmdlIHRoZSBkYXRhIGZyYW1lcyBiYXNlZCBvbiB0aGUgJ2dyb3VwJyBjb2x1bW4KcmVzdWx0X01TRSA8LSBtZXJnZShtZWFuX3ZhbHVlc19NU0UsIG1heF92YWx1ZXNfTVNFLCBieSA9ICJncm91cCIsIHN1ZmZpeGVzID0gYygiX21lYW4iLCAiX21heCIpKQpyZXN1bHRfTVNFIDwtIG1lcmdlKHJlc3VsdF9NU0UsIG1pbl92YWx1ZXNfTVNFLCBieSA9ICJncm91cCIsIHN1ZmZpeGVzID0gYygiIiwgIl9taW4iKSkKcmVzdWx0X01TRSA8LSBtZXJnZShyZXN1bHRfTVNFLCBtaW5fdmFsdWVzX01TRSwgYnkgPSAiZ3JvdXAiLCBzdWZmaXhlcyA9IGMoIiIsICJfbWluIikpCnJlc3VsdF9NU0UgPC0gbWVyZ2UocmVzdWx0X01TRSwgdmFyaWFuY2VzX01TRSwgYnkgPSAiZ3JvdXAiLCBzdWZmaXhlcyA9IGMoIiIsICJfdmFyIikpCgojIEFzc3VtaW5nIHlvdSBoYXZlIHRoZSAndmFsdWUnIGNvbHVtbiBpbiB5b3VyIGRhdGEgZnJhbWUgJ3Jlc3VsdCcKcmVzdWx0X01TRSA8LSByZXN1bHRfTVNFWywgIShuYW1lcyhyZXN1bHRfTVNFKSAlaW4lICJ2YWx1ZSIpXQoKIyBDb252ZXJ0IHRoZSBkYXRhIGZyYW1lIHRvIExhVGVYIGZvcm1hdCB1c2luZyB4dGFibGUKbGF0ZXhfY29kZV9NU0UgPC0geHRhYmxlKHJlc3VsdF9NU0UpCgojIFByaW50IHRoZSBMYVRlWCBjb2RlCnByaW50KGxhdGV4X2NvZGVfTVNFKQpgYGAKCgpSMgpgYGB7cn0KIyBDcmVhdGUgYSBkYXRhIGZyYW1lCmRmX1IyIDwtIGRhdGEuZnJhbWUoeCA9IDE6bGVuZ3RoKE1DX3Blcl9zdGF0aXN0aWMkUjIkTEFTU08pLCB2YWx1ZSA9IGMoTUNfcGVyX3N0YXRpc3RpYyRSMiRMQVNTTywgTUNfcGVyX3N0YXRpc3RpYyRSMiRSRiwgTUNfcGVyX3N0YXRpc3RpYyRSMiRYZ0IsIE1DX3Blcl9zdGF0aXN0aWMkUjIkS2VybmVsS25uLCBNQ19wZXJfc3RhdGlzdGljJFIyJEpvaW50TSksIGdyb3VwID0gcmVwKG1vZGVsc191cCwgZWFjaCA9IGxlbmd0aChNQ19wZXJfc3RhdGlzdGljJFIyJExBU1NPKSkpCgojIENhbGN1bGF0ZSBtZWFuIHZhbHVlcyBmb3IgeCBhbmQgeQptZWFuX3ZhbHVlc19SMiA8LSBhZ2dyZWdhdGUodmFsdWUgfiBncm91cCwgZGF0YSA9IGRmX1IyLCBtZWFuKQptYXhfdmFsdWVzX1IyIDwtIGFnZ3JlZ2F0ZSh2YWx1ZSB+IGdyb3VwLCBkYXRhID0gZGZfUjIsIG1heCkKbWluX3ZhbHVlc19SMiA8LSBhZ2dyZWdhdGUodmFsdWUgfiBncm91cCwgZGF0YSA9IGRmX1IyLCBtaW4pCnZhcmlhbmNlc19SMiA8LSBhZ2dyZWdhdGUodmFsdWUgfiBncm91cCwgZGF0YSA9IGRmX1IyLCB2YXIpCgojIENyZWF0ZSBhIGxpbmUgcGxvdApnZ3Bsb3QoZGZfUjIsIGFlcyh4ID0geCwgeSA9IHZhbHVlLCBjb2xvciA9IGdyb3VwLCBncm91cCA9IGdyb3VwKSkgKwogIGdlb21fbGluZSgpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21faGxpbmUoZGF0YSA9IG1heF92YWx1ZXNfUjIsIGFlcyh5aW50ZXJjZXB0ID0gdmFsdWUsIGNvbG9yID0gZ3JvdXAsIGxpbmV0eXBlID0gImRhc2hlZCIpLCBzaXplID0gMS4wKSArCiAgZ2VvbV9obGluZShkYXRhID0gbWluX3ZhbHVlc19SMiwgYWVzKHlpbnRlcmNlcHQgPSB2YWx1ZSwgY29sb3IgPSBncm91cCwgbGluZXR5cGUgPSAiZGFzaGVkIiksIHNpemUgPSAxLjApICsKICBsYWJzKHRpdGxlID0gIiIsCiAgICAgICB4ID0gIlNlZWQiLAogICAgICAgeSA9ICJSMiIsCiAgICAgICBjb2xvciA9ICJHcm91cCIpICsKICB0aGVtZV9taW5pbWFsKCkKCiMgRGVmaW5lIHRoZSBwYXRoIGZvciB0aGUgUE5HIGltYWdlCk1DX01MX1IyIDwtICIvVXNlcnMvYm9uam91ci9Eb2N1bWVudHMvTWFzdGVyIGluIEVjb25vbWljcyBCb25uLzV0aCBzZW1lc3Rlci9UaGVzaXMvUi1Db2RlL0RyYWZ0cy8xMXRoIERyYWZ0IC0gQWR2YW5jZWQgZnVuY3Rpb24gYW5kIE1vbnRlY2FybG8vSW1hZ2VzIE1vbnRlY2FybG8vTUNfTUxfUjIucG5nIgoKIyBTYXZlIHRoZSBnZ3Bsb3QgYXMgYSBQTkcgaW1hZ2UKZ2dzYXZlKGZpbGVuYW1lID0gTUNfTUxfUjIsIHBsb3QgPSBsYXN0X3Bsb3QoKSwgd2lkdGggPSA2LCBoZWlnaHQgPSA0LCBkcGkgPSAzMDApCgpgYGAKCmBgYHtyfQojIE1lcmdlIHRoZSBkYXRhIGZyYW1lcyBiYXNlZCBvbiB0aGUgJ2dyb3VwJyBjb2x1bW4KcmVzdWx0X1IyIDwtIG1lcmdlKG1lYW5fdmFsdWVzX1IyLCBtYXhfdmFsdWVzX1IyLCBieSA9ICJncm91cCIsIHN1ZmZpeGVzID0gYygiX21lYW4iLCAiX21heCIpKQpyZXN1bHRfUjIgPC0gbWVyZ2UocmVzdWx0X1IyLCBtaW5fdmFsdWVzX1IyLCBieSA9ICJncm91cCIsIHN1ZmZpeGVzID0gYygiIiwgIl9taW4iKSkKcmVzdWx0X1IyIDwtIG1lcmdlKHJlc3VsdF9SMiwgbWluX3ZhbHVlc19SMiwgYnkgPSAiZ3JvdXAiLCBzdWZmaXhlcyA9IGMoIiIsICJfbWluIikpCnJlc3VsdF9SMiA8LSBtZXJnZShyZXN1bHRfUjIsIHZhcmlhbmNlc19SMiwgYnkgPSAiZ3JvdXAiLCBzdWZmaXhlcyA9IGMoIiIsICJfdmFyIikpCgojIEFzc3VtaW5nIHlvdSBoYXZlIHRoZSAndmFsdWUnIGNvbHVtbiBpbiB5b3VyIGRhdGEgZnJhbWUgJ3Jlc3VsdCcKcmVzdWx0X1IyIDwtIHJlc3VsdF9SMlssICEobmFtZXMocmVzdWx0X1IyKSAlaW4lICJ2YWx1ZSIpXQoKIyBDb252ZXJ0IHRoZSBkYXRhIGZyYW1lIHRvIExhVGVYIGZvcm1hdCB1c2luZyB4dGFibGUKbGF0ZXhfY29kZV9SMiA8LSB4dGFibGUocmVzdWx0X1IyKQoKIyBQcmludCB0aGUgTGFUZVggY29kZQpwcmludChsYXRleF9jb2RlX1IyKQpgYGAKCgoKIyBSRVNVTFRTIE9GIFRIRSBEUkREIFNJTVVMQVRJT05TCk5vdyB0aGUgcmVzdWx0cyBvZiB0aGUgTU9OVEVDQVJMT1MgZm9yIERSREQKYGBge3J9Ck1vbnRlQ2FybG8yX3Jlc3VsdHMgPC0gTW9udGVDYXJsb19EUkREKG4sIHNpZ21hLCBtdSwgYmV0YS50cnVlLCBiZXRhLmQsIHByb2JhYmlsaXR5LAogICAgICAgICAgICAgICAgICAgICAgIG51bV9zaW11bGF0aW9ucywKICAgICAgICAgICAgICAgICAgICAgICBzdGFydGluZ190ZXN0X3BlcmlvZCwgZW5kaW5nX3Rlc3RfcGVyaW9kKQpgYGAKCkxldCdzIGNoZWNrIHRoZSBhdmVyYWdlIGxlbmd0aCBvZiB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbHMgYWJvdmUgYW5kIHRoZSB0aW1lcyB0aGUgQVRUIGFjdHVhbGx5IGZhbGxzIHdpdGhpbiB0aG9zZSBDSQpgYGB7cn0KIyBJbml0aWFsaXplIG1hdHJpY2VzIG91dHNpZGUgdGhlIGxvb3AKdWNpIDwtIG1hdHJpeChOQSwgbnJvdyA9IG51bV9zaW11bGF0aW9ucywgbmNvbCA9IGVuZGluZ190ZXN0X3BlcmlvZCAtIHBlcmlvZF90cmVhdG1lbnQgKyAxKQpsY2kgPC0gbWF0cml4KE5BLCBucm93ID0gbnVtX3NpbXVsYXRpb25zLCBuY29sID0gZW5kaW5nX3Rlc3RfcGVyaW9kIC0gcGVyaW9kX3RyZWF0bWVudCArIDEpCgojIEF2ZXJhZ2UgbGVuZ3RoCmxlbmd0aF9NQ19EUkREIDwtIG1hdHJpeChOQSwgbnJvdyA9IG51bV9zaW11bGF0aW9ucywgbmNvbCA9IGVuZGluZ190ZXN0X3BlcmlvZCAtIHBlcmlvZF90cmVhdG1lbnQgKyAxKQoKZm9yIChpIGluIDE6bnVtX3NpbXVsYXRpb25zKSB7CiAgCiAgZm9yIChwIGluIHBlcmlvZF90cmVhdG1lbnQ6ZW5kaW5nX3Rlc3RfcGVyaW9kKSB7CiAgICAKICAgIHVjaVtpLCBwIC0gcGVyaW9kX3RyZWF0bWVudCArIDFdIDwtIE1vbnRlQ2FybG8yX3Jlc3VsdHNbW3Bhc3RlKCJTaW11bGF0aW9uIiwgaSwgc2VwID0gIiIpXV1bW3Bhc3RlKCJEUkREX3QiLCBwLCBzZXAgPSAiIildXSR1Y2kKICAgIGxjaVtpLCBwIC0gcGVyaW9kX3RyZWF0bWVudCArIDFdIDwtIE1vbnRlQ2FybG8yX3Jlc3VsdHNbW3Bhc3RlKCJTaW11bGF0aW9uIiwgaSwgc2VwID0gIiIpXV1bW3Bhc3RlKCJEUkREX3QiLCBwLCBzZXAgPSAiIildXSRsY2kKICAgIAogICAgbGVuZ3RoX01DX0RSRERbaSwgcCAtIHBlcmlvZF90cmVhdG1lbnQgKyAxXSA8LSB1Y2lbaSwgcCAtIHBlcmlvZF90cmVhdG1lbnQgKyAxXSAtIGxjaVtpLCBwIC0gcGVyaW9kX3RyZWF0bWVudCArIDFdCiAgICAKICB9CiAgCn0KCiMgQ2FsY3VsYXRlIGF2ZXJhZ2VzIHBlciBjb2x1bW4gd2l0aG91dCBtb2RpZnlpbmcgeW91ciBjb2RlCnVjaV9hdmVyYWdlc19NQ19EUkREIDwtIGFwcGx5KHVjaSwgMiwgbWVhbikKbGNpX2F2ZXJhZ2VzX01DX0RSREQgPC0gYXBwbHkobGNpLCAyLCBtZWFuKQpsZW5ndGhfYXZlcmFnZXNfTUNfRFJERCA8LSBhcHBseShsZW5ndGhfTUNfRFJERCwgMiwgbWVhbikKCiMgSSBhbSBqdXN0IG1pc3NpbmcgdGhlIGFtb3VudCBvZiB0aW1lcyB0aGUgQVRUIGZhbGxzIGluc2lkZSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIEluaXRpYWxpemUgbWF0cmljZXMgb3V0c2lkZSB0aGUgbG9vcApBVFRfTUNfRFJERCA8LSBtYXRyaXgoTkEsIG5yb3cgPSBudW1fc2ltdWxhdGlvbnMsIG5jb2wgPSBlbmRpbmdfdGVzdF9wZXJpb2QgLSBwZXJpb2RfdHJlYXRtZW50ICsgMSkKCiMgZm9yIHRoZSBjb3VudGVyIHRoYXQgd2lsbCBicmluZyBtZSB0aGUgdGltZXMgaXQgYWN0dWFsbHkgZmFsbHMgaW5zaWRlIHRoZSBjb25maWRlbmNlIGludGVydmFsCkNJX1RpbWVzX2ZhbGxfaW5zaWRlX0RSREQgPC0gbWF0cml4KE5BLCBucm93ID0gMSwgbmNvbCA9IGVuZGluZ190ZXN0X3BlcmlvZCAtIHBlcmlvZF90cmVhdG1lbnQgKyAxKQoKZm9yIChwIGluIHBlcmlvZF90cmVhdG1lbnQ6ZW5kaW5nX3Rlc3RfcGVyaW9kKSB7CiAgCiAgY291bnRlcl9BVFRfRFJERF9NQyA8LSAwCiAgCiAgZm9yIChpIGluIDE6bnVtX3NpbXVsYXRpb25zKSB7CiAgICAKICAgICMgVG8gcmVjb3ZlciB0aGUgQVRUIHZhbHVlCiAgICBBVFRfTUNfRFJERFtpLCBwIC0gcGVyaW9kX3RyZWF0bWVudCArIDFdIDwtIE1vbnRlQ2FybG8yX3Jlc3VsdHNbW3Bhc3RlKCJTaW11bGF0aW9uIiwgaSwgc2VwID0gIiIpXV1bW3Bhc3RlKCJEUkREX3QiLCBwLCBzZXAgPSAiIildXSRBVFQKICAgIAogICAgIyBUbyBnZXQgdGhlIHRpbWVzIHRoZSBBVFQgdmFsdWUgZmFsbHMgaW5zaWRlIHRoZSBDSQogICAgaWYobGNpX2F2ZXJhZ2VzX01DX0RSRERbcCAtIHBlcmlvZF90cmVhdG1lbnQgKyAxXSA8IEFUVF9NQ19EUkREW2ksIHAgLSBwZXJpb2RfdHJlYXRtZW50ICsgMV0gJiBBVFRfTUNfRFJERFtpLCBwIC0gcGVyaW9kX3RyZWF0bWVudCArIDFdIDwgdWNpX2F2ZXJhZ2VzX01DX0RSRERbcCAtIHBlcmlvZF90cmVhdG1lbnQgKyAxXSl7CiAgICAgIAogICAgICBjb3VudGVyX0FUVF9EUkREX01DIDwtIGNvdW50ZXJfQVRUX0RSRERfTUMgKyAxCiAgICAgIAogICAgfSBlbHNlIHsKICAgICAgCiAgICAgIGNvdW50ZXJfQVRUX0RSRERfTUMgPC0gY291bnRlcl9BVFRfRFJERF9NQyArIDAKICAgIH0KICAgIAogIH0KICAKICBDSV9UaW1lc19mYWxsX2luc2lkZV9EUkREWzEsIHAgLSBwZXJpb2RfdHJlYXRtZW50ICsgMV0gPC0gY291bnRlcl9BVFRfRFJERF9NQwogIAp9CgpgYGAKCkxldCdzIG1ha2UgYSBncmFwaApgYGB7cn0KIyBDcmVhdGUgYSBkYXRhIGZyYW1lIGZvciB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbHMKRGF0YV9wbG90X0NJX01DX0RSREQgPC0gZGF0YS5mcmFtZSgKICBwZXJpb2QgPSBzZXEocGVyaW9kX3RyZWF0bWVudCwgZW5kaW5nX3Rlc3RfcGVyaW9kLCBieSA9IDEpLAogIFVwcGVyX0NJID0gdWNpX2F2ZXJhZ2VzX01DX0RSREQsCiAgTG93ZXJfQ0kgPSBsY2lfYXZlcmFnZXNfTUNfRFJERAopCgojIFRoZSBncmFwaApnZ3Bsb3QoRGF0YV9wbG90X0NJX01DX0RSREQsIGFlcyh4ID0gcGVyaW9kKSkgKwogIGdlb21fcG9pbnQoYWVzKHkgPSBVcHBlcl9DSSksIGNvbG9yID0gImJsdWUiLCBzaXplID0gMykgKwogIGdlb21fcG9pbnQoYWVzKHkgPSBMb3dlcl9DSSksIGNvbG9yID0gInJlZCIsIHNpemUgPSAzKSArCiAgZ2VvbV9saW5lKGFlcyh5ID0gVXBwZXJfQ0kpLCBjb2xvciA9ICJibHVlIikgKwogIGdlb21fbGluZShhZXMoeSA9IExvd2VyX0NJKSwgY29sb3IgPSAicmVkIikgKwogIGdlb21fc2VnbWVudChhZXMoeCA9IHBlcmlvZCwgeGVuZCA9IHBlcmlvZCwgeSA9IExvd2VyX0NJLCB5ZW5kID0gVXBwZXJfQ0kpLCBjb2xvciA9ICJncmF5IiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJBdmVyYWdlIFRyZWF0bWVudCBFZmZlY3QgKEFUVCkgQ29uZmlkZW5jZSBJbnRlcnZhbHMiLAogICAgeCA9ICJQZXJpb2QiLAogICAgeSA9ICJBVFQiCiAgKSArCiAgdGhlbWVfbWluaW1hbCgpCgojIERlZmluZSB0aGUgcGF0aCBmb3IgdGhlIFBORyBpbWFnZQpDSV9NQ19EUkREIDwtICIvVXNlcnMvYm9uam91ci9Eb2N1bWVudHMvTWFzdGVyIGluIEVjb25vbWljcyBCb25uLzV0aCBzZW1lc3Rlci9UaGVzaXMvUi1Db2RlL0RyYWZ0cy8xNHRoIERyYWZ0L0ltYWdlcy9DSV9NQ19EUkRELnBuZyIKCiMgU2F2ZSB0aGUgZ2dwbG90IGFzIGEgUE5HIGltYWdlCmdnc2F2ZShmaWxlbmFtZSA9IENJX01DX0RSREQsIHBsb3QgPSBsYXN0X3Bsb3QoKSwgd2lkdGggPSA2LCBoZWlnaHQgPSA0LCBkcGkgPSAzMDApCmBgYApMZXQncyBnZXQgYSB0YWJsZQpgYGB7cn0KIyBUYWtpbmcgdGhlIHJvdyBhdmVyYWdlcwpsYV9NQ19EUkREIDwtIG1hdHJpeChjKGxlbmd0aF9hdmVyYWdlc19NQ19EUkRELCBtZWFuKGxlbmd0aF9hdmVyYWdlc19NQ19EUkREKSksIG5yb3cgPSAxKQp0Zl9NQ19EUkREIDwtIGNiaW5kKENJX1RpbWVzX2ZhbGxfaW5zaWRlX0RSREQsIHJvd01lYW5zKENJX1RpbWVzX2ZhbGxfaW5zaWRlX0RSREQpKQoKIyBOb3cgYSByb3cgYmluZApUYWJsZV9NQ19EUkREIDwtIHJiaW5kKGxhX01DX0RSREQsIHRmX01DX0RSREQpCgojIE5vdyB0cmFuc2Zvcm0gaXQgaW50byBhIGRhdGFmcmFtZQpUYWJsZV9NQ19EUkRELmRmIDwtIGFzLmRhdGEuZnJhbWUoVGFibGVfTUNfRFJERCkKCiMgIyBDcmVhdGUgYSBkYXRhZnJhbWUKIyBUYWJsZV9DSV9EUkREX01DIDwtIGRhdGEuZnJhbWUoCiMgICBsZW5ndGhfYXZlcmFnZXNfTUNfRFJERCA9IGxhX01DX0RSREQsCiMgICBDSV9UaW1lc19mYWxsX2luc2lkZV9EUkREID0gdGZfTUNfRFJERAojICkKCiMgQWRkIGNvbHVtbiBuYW1lcwpjb2xuYW1lcyhUYWJsZV9NQ19EUkRELmRmKSA8LSBjKCJ0MyIsICJ0NCIsICJ0NSIsICJhdmVyYWdlIikgCgojIEFkZCByb3cgbmFtZXMKcm93bmFtZXMoVGFibGVfTUNfRFJERC5kZikgPC0gYygiYXZlcmFnZSBsZW5ndGggb2YgdGhlIENJIiwgInRpbWVzIHRoZSBBVFQgZmFsbHMgaW5zaWRlIHRoZSBDSSIpCgojIENvbnZlcnQgdGhlIGRhdGEgZnJhbWUgdG8gTGFUZVggZm9ybWF0IHVzaW5nIHh0YWJsZQpsYXRleF9UYWJsZV9NQ19EUkRELmRmIDwtIHh0YWJsZShUYWJsZV9NQ19EUkRELmRmKQoKIyBQcmludCB0aGUgTGFUZVggY29kZQpwcmludChsYXRleF9UYWJsZV9NQ19EUkRELmRmKQpgYGAKCgpMZXQncyBzdG9yZSBvdXIgdmFsdWVzIApgYGB7cn0KIyBEZWZpbmluZyB0aGUgdmVjdG9ycyB0byBzdG9yZSB0aGUgdmFyaWFibGVzCk1vbnRlQ2FybG9fRFJERF9BVFQgPC0gbWF0cml4KG5yb3cgPSBudW1fc2ltdWxhdGlvbnMsIG5jb2wgPSBlbmRpbmdfdGVzdF9wZXJpb2QgLSBzdGFydGluZ190ZXN0X3BlcmlvZCArIDEpCk1vbnRlQ2FybG9fRFJERF9TRSA8LSBtYXRyaXgobnJvdyA9IG51bV9zaW11bGF0aW9ucywgbmNvbCA9IGVuZGluZ190ZXN0X3BlcmlvZCAtIHN0YXJ0aW5nX3Rlc3RfcGVyaW9kICsgMSkKCmZvciAoeCBpbiBzdGFydGluZ190ZXN0X3BlcmlvZDplbmRpbmdfdGVzdF9wZXJpb2QpIHsKICAKICBmb3IgKGkgaW4gMTpudW1fc2ltdWxhdGlvbnMpIHsKICAgICMgRmlsbGluZyB1cCBvdXIgbGlzdHMKICAgIE1vbnRlQ2FybG9fRFJERF9BVFRbaSwgeCAtIHN0YXJ0aW5nX3Rlc3RfcGVyaW9kICsgMV0gPC0gTW9udGVDYXJsbzJfcmVzdWx0c1tbcGFzdGUoIlNpbXVsYXRpb24iLCBpLCBzZXAgPSAiIildXVtbcGFzdGUoIkRSRERfdCIsIHgsIHNlcCA9ICIiKV1dJEFUVAogICAgTW9udGVDYXJsb19EUkREX1NFW2ksIHggLSBzdGFydGluZ190ZXN0X3BlcmlvZCArIDFdIDwtIE1vbnRlQ2FybG8yX3Jlc3VsdHNbW3Bhc3RlKCJTaW11bGF0aW9uIiwgaSwgc2VwID0gIiIpXV1bW3Bhc3RlKCJEUkREX3QiLCB4LCBzZXAgPSAiIildXSRzZQogIH0KfQoKIyBDYWxjdWxhdGUgcm93LXdpc2UgbWVhbgphdmVyYWdlX0FUVCA8LSByb3dNZWFucyhNb250ZUNhcmxvX0RSRERfQVRULCBuYS5ybSA9IFRSVUUpCmF2ZXJhZ2VfU0UgPC0gcm93TWVhbnMoTW9udGVDYXJsb19EUkREX1NFLCBuYS5ybSA9IFRSVUUpCgojIEFkZCBuZXcgY29sdW1uICJBdmVyYWdlIiB0byB0aGUgbWF0cmljZXMKTW9udGVDYXJsb19EUkREX0FUVCA8LSBjYmluZChNb250ZUNhcmxvX0RSRERfQVRULCBBdmVyYWdlID0gYXZlcmFnZV9BVFQpCk1vbnRlQ2FybG9fRFJERF9TRSA8LSBjYmluZChNb250ZUNhcmxvX0RSRERfU0UsIEF2ZXJhZ2UgPSBhdmVyYWdlX1NFKQoKI1RyYW5zZm9ybSB0aGVtIHRvIERhdGEgRnJhbWUKTW9udGVDYXJsb19EUkREX0FUVF9kZiA8LSBhcy5kYXRhLmZyYW1lKE1vbnRlQ2FybG9fRFJERF9BVFQpCk1vbnRlQ2FybG9fRFJERF9TRV9kZiA8LSBhcy5kYXRhLmZyYW1lKE1vbnRlQ2FybG9fRFJERF9TRSkKCmBgYAoKR2V0dGluZyBzb21lIHN0YXRpc3RpY3MgZm9yIG91ciBMYVRlWCBUYWJsZQpgYGB7cn0KTW9udGVDYXJsb19EUkREX2ZvclRhYmxlIDwtIHJiaW5kKGNiaW5kKG1lYW4oTW9udGVDYXJsb19EUkREX0FUVF9kZiRBdmVyYWdlKSwgbWluKE1vbnRlQ2FybG9fRFJERF9BVFRfZGYkQXZlcmFnZSksIG1heChNb250ZUNhcmxvX0RSRERfQVRUX2RmJEF2ZXJhZ2UpLCB2YXIoTW9udGVDYXJsb19EUkREX0FUVF9kZiRBdmVyYWdlKSksIGNiaW5kKG1lYW4oTW9udGVDYXJsb19EUkREX1NFX2RmJEF2ZXJhZ2UpLCBtaW4oTW9udGVDYXJsb19EUkREX1NFX2RmJEF2ZXJhZ2UpLCBtYXgoTW9udGVDYXJsb19EUkREX1NFX2RmJEF2ZXJhZ2UpLCB2YXIoTW9udGVDYXJsb19EUkREX1NFX2RmJEF2ZXJhZ2UpKSkKCiMgQWRkIHJvdyBuYW1lcwpyb3cubmFtZXMoTW9udGVDYXJsb19EUkREX2ZvclRhYmxlKSA8LSBjKCJBVFQiLCAiU0UiKQoKIyBBZGQgY29sIG5hbWVzCmNvbG5hbWVzKE1vbnRlQ2FybG9fRFJERF9mb3JUYWJsZSkgPC0gYygibWVhbiIsICJtaW4iLCAibWF4IiwgInZhciIpCgojIENvbnZlcnQgdGhlIGRhdGEgZnJhbWUgdG8gTGFUZVggZm9ybWF0IHVzaW5nIHh0YWJsZQpsYXRleF9jb2RlX0REUkQgPC0geHRhYmxlKE1vbnRlQ2FybG9fRFJERF9mb3JUYWJsZSkKCiMgUHJpbnQgdGhlIExhVGVYIGNvZGUKcHJpbnQobGF0ZXhfY29kZV9ERFJEKQoKYGBgCgoKR1JBUEhTCgpBVFQKYGBge3J9CiMgQ2FsY3VsYXRlIG92ZXJhbGwgbWVhbgpvdmVyYWxsX21lYW5fQVRUIDwtIG1lYW4oTW9udGVDYXJsb19EUkREX0FUVF9kZiRBdmVyYWdlLCBuYS5ybSA9IFRSVUUpCgpnZ3Bsb3QoZGF0YSA9IE1vbnRlQ2FybG9fRFJERF9BVFRfZGYsIGFlcyh4ID0gMTpsZW5ndGgoQXZlcmFnZSksIHkgPSBBdmVyYWdlKSkgKwogIGdlb21fbGluZSgpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IG92ZXJhbGxfbWVhbl9BVFQsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gInJlZCIsIHNpemUgPSAxLjApICsKICBsYWJzKHRpdGxlID0gIkRSREQgTW9udGVDYXJsbyBzaW11bGF0aW9uIGF2ZXJhZ2UgQVRUIHBlciBzaW11bGF0aW9uIiwKICAgICAgIHggPSAiU2VlZCIsCiAgICAgICB5ID0gIkFUVCIsCiAgICAgICBjYXB0aW9uID0gIk5vdGU6IFJlZCBkYXNoZWQgbGluZSByZXByZXNlbnRzIGF2ZXJhZ2UgYWNyb3NzIHNpbXVsYXRpb25zIikgKwogIHRoZW1lX21pbmltYWwoKQoKIyBEZWZpbmUgdGhlIHBhdGggZm9yIHRoZSBQTkcgaW1hZ2UKTUNfRFJERF9BVFQgPC0gIi9Vc2Vycy9ib25qb3VyL0RvY3VtZW50cy9NYXN0ZXIgaW4gRWNvbm9taWNzIEJvbm4vNXRoIHNlbWVzdGVyL1RoZXNpcy9SLUNvZGUvRHJhZnRzLzExdGggRHJhZnQgLSBBZHZhbmNlZCBmdW5jdGlvbiBhbmQgTW9udGVjYXJsby9JbWFnZXMgTW9udGVjYXJsby9NQ19EUkREX0FUVC5wbmciCgojIFNhdmUgdGhlIGdncGxvdCBhcyBhIFBORyBpbWFnZQpnZ3NhdmUoZmlsZW5hbWUgPSBNQ19EUkREX0FUVCwgcGxvdCA9IGxhc3RfcGxvdCgpLCB3aWR0aCA9IDYsIGhlaWdodCA9IDQsIGRwaSA9IDMwMCkKCmBgYAoKU0UKYGBge3J9CiMgQ2FsY3VsYXRlIG92ZXJhbGwgbWVhbgpvdmVyYWxsX21lYW5fU0UgPC0gbWVhbihNb250ZUNhcmxvX0RSRERfU0VfZGYkQXZlcmFnZSwgbmEucm0gPSBUUlVFKQoKZ2dwbG90KGRhdGEgPSBNb250ZUNhcmxvX0RSRERfU0VfZGYsIGFlcyh4ID0gMTpsZW5ndGgoQXZlcmFnZSksIHkgPSBBdmVyYWdlKSkgKwogIGdlb21fbGluZSgpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IG92ZXJhbGxfbWVhbl9TRSwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAicmVkIiwgc2l6ZSA9IDEuMCkgKwogIGxhYnModGl0bGUgPSAiRFJERCBNb250ZUNhcmxvIHNpbXVsYXRpb24gYXZlcmFnZSBTRSBwZXIgc2ltdWxhdGlvbiIsCiAgICAgICB4ID0gIlNlZWQiLAogICAgICAgeSA9ICJTRSIsCiAgICAgICBjYXB0aW9uID0gIk5vdGU6IFJlZCBkYXNoZWQgbGluZSByZXByZXNlbnRzIGF2ZXJhZ2UgYWNyb3NzIHNpbXVsYXRpb25zIikgKwogIHRoZW1lX21pbmltYWwoKQoKIyBEZWZpbmUgdGhlIHBhdGggZm9yIHRoZSBQTkcgaW1hZ2UKTUNfRFJERF9TRSA8LSAiL1VzZXJzL2JvbmpvdXIvRG9jdW1lbnRzL01hc3RlciBpbiBFY29ub21pY3MgQm9ubi81dGggc2VtZXN0ZXIvVGhlc2lzL1ItQ29kZS9EcmFmdHMvMTF0aCBEcmFmdCAtIEFkdmFuY2VkIGZ1bmN0aW9uIGFuZCBNb250ZWNhcmxvL0ltYWdlcyBNb250ZWNhcmxvL01DX0RSRERfU0UucG5nIgoKIyBTYXZlIHRoZSBnZ3Bsb3QgYXMgYSBQTkcgaW1hZ2UKZ2dzYXZlKGZpbGVuYW1lID0gTUNfRFJERF9TRSwgcGxvdCA9IGxhc3RfcGxvdCgpLCB3aWR0aCA9IDYsIGhlaWdodCA9IDQsIGRwaSA9IDMwMCkKYGBgCgoKIyBOT1cgTEVUJ1MgV09SSyBXSVRIIFJFQUwgV09STEQgREFUQSBBUyBBTiBFTVBJUklDQUwgQVBQTElDQVRJT04gIyMjIyMjIyMjIyMjIyMKCmBgYHtyfQpOU1dfRGF0YSA8LSBhcy5kYXRhLmZyYW1lKG5zdykKZGVzY3JpYmUoTlNXX0RhdGEpCmBgYAoKYGBge3J9Ck5TV19EYXRhCmBgYApMZXQncyBnZXQgYSBzdW1tYXJ5IG9mIHRoZSBOU1cgZm9yIExhTG9uZGUKYGBge3J9Ck5TV19EYXRhX0xhbG9uZGUgPC0gc3Vic2V0KE5TV19EYXRhLCBzYW1wbGUgPT0gMSkKTlNXX0RhdGFfTGFsb25kZQpgYGAKCmBgYHtyfQojIENhbGN1bGF0ZSBzdW1tYXJ5IHN0YXRpc3RpY3MgYnkgJ3RyZWF0ZWQnIHN0YXR1cwpzdW1tYXJ5X3RyZWF0ZWQgPC0gTlNXX0RhdGFfTGFsb25kZSAlPiUKICBncm91cF9ieSh0cmVhdGVkKSAlPiUKICBzdW1tYXJpc2UoY291bnQgPSBuKCksIGFjcm9zcyhjKGFnZSwgZWR1YywgYmxhY2ssIG1hcnJpZWQsIG5vZGVncmVlLCByZTc0LCByZTc1LCByZTc4LCBoaXNwKSwgbWVhbikpICU+JQogIHQoKSAlPiUKICBhcy5kYXRhLmZyYW1lKCkKCiMgQ2FsY3VsYXRlIHN1bW1hcnkgc3RhdGlzdGljcyBieSAnZHdpbmNsJyBzdGF0dXMKc3VtbWFyeV9kd2luY2wgPC0gTlNXX0RhdGFfTGFsb25kZSAlPiUKICBncm91cF9ieShkd2luY2wpICU+JQogIHN1bW1hcmlzZShjb3VudCA9IG4oKSwgYWNyb3NzKGMoYWdlLCBlZHVjLCBibGFjaywgbWFycmllZCwgbm9kZWdyZWUsIHJlNzQsIHJlNzUsIHJlNzgsIGhpc3ApLCBtZWFuKSkgJT4lCiAgdCgpICU+JQogIGFzLmRhdGEuZnJhbWUoKQoKIyBDYWxjdWxhdGUgZGlmZmVyZW5jZXMgYmV0d2VlbiB0cmVhdGVkIGFuZCB1bnRyZWF0ZWQgZ3JvdXBzCnN1bW1hcnlfdHJlYXRlZCREaWZmZXJlbmNlIDwtIHN1bW1hcnlfdHJlYXRlZCRWMiAtIHN1bW1hcnlfdHJlYXRlZCRWMQpzdW1tYXJ5X2R3aW5jbCREaWZmZXJlbmNlIDwtIHN1bW1hcnlfZHdpbmNsJFYyIC0gc3VtbWFyeV9kd2luY2wkVjEKCiMgUmVtb3ZlICd0cmVhdGVkJyByb3cKc3VtbWFyeV90cmVhdGVkIDwtIHN1bW1hcnlfdHJlYXRlZFstMSwgXQpzdW1tYXJ5X2R3aW5jbCA8LSBzdW1tYXJ5X2R3aW5jbFstMSwgXQoKIyBSZW5hbWUgY29sdW1ucwpjb2xuYW1lcyhzdW1tYXJ5X3RyZWF0ZWQpIDwtIGMoIk1lYW5fVW50cmVhdGVkIiwgIk1lYW5fVHJlYXRlZCIsICJEaWZmZXJlbmNlIikKY29sbmFtZXMoc3VtbWFyeV9kd2luY2wpIDwtIGMoIk1lYW5fVW50cmVhdGVkIiwgIk1lYW5fVHJlYXRlZCIsICJEaWZmZXJlbmNlIikKCiMgQ29udmVydCB0YWJsZXMgdG8gTGFUZVggZm9ybWF0IHVzaW5nIHh0YWJsZQpzdW1tYXJ5X3RyZWF0ZWRfbGF0ZXggPC0geHRhYmxlKHN1bW1hcnlfdHJlYXRlZCwgY2FwdGlvbiA9ICJTdW1tYXJ5IHN0YXRpc3RpY3MgYnkgdHJlYXRtZW50IHN0YXR1cyIsIGxhYmVsID0gInRhYjp0cmVhdGVkX3N1bW1hcnkiKQpzdW1tYXJ5X2R3aW5jbF9sYXRleCA8LSB4dGFibGUoc3VtbWFyeV9kd2luY2wsIGNhcHRpb24gPSAiU3VtbWFyeSBzdGF0aXN0aWNzIGJ5IGR3aW5jbCBzdGF0dXMiLCBsYWJlbCA9ICJ0YWI6ZHdpbmNsX3N1bW1hcnkiKQpgYGAKCmxhbG9uZGUKYGBge3J9CnByaW50KHN1bW1hcnlfdHJlYXRlZF9sYXRleCwpCmBgYAoKZHdpbmNsCmBgYHtyfQpwcmludChzdW1tYXJ5X2R3aW5jbF9sYXRleCwpCmBgYAoKTGV0J3MgZ2V0IHJpZCBvZmYgdGhlIHZhcmlhYmxlcyB0aGF0IHdlIGRvIG5vdCBuZWVkCmBgYHtyfQpOU1dfRGF0YV9MYWxvbmRlX2NsZWFuZWQgPC0gTlNXX0RhdGFfTGFsb25kZVssICEobmFtZXMoTlNXX0RhdGFfTGFsb25kZSkgJWluJSBjKCJlYXJseV9yYSIsICJzYW1wbGUiLCAiZXhwZXJpbWVudGFsIikpXQpOU1dfRGF0YV9MYWxvbmRlX2NsZWFuZWQgCmBgYAoKTGV0J3MgcmVjb3ZlciB0aGUgQVRUIGJ5IHVzaW5nIHRoZSBjYXN1YWwgZWZmZWN0cyBwYWNrYWdlCmBgYHtyfQojIERlZmluZSBjb3ZhcmlhdGVzCmNvdmFyaWF0ZXMgPC0gYygnYWdlJywgJ2VkdWMnLCAnYmxhY2snLCAnaGlzcCcsICdtYXJyaWVkJywgJ25vZGVncmVlJywgJ3JlNzUnKQoKIyBGaXQgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbCB0byBlc3RpbWF0ZSBwcm9wZW5zaXR5IHNjb3Jlcwpwc19tb2RlbCA8LSBnbG0odHJlYXRlZCB+IGFnZSArIGVkdWMgKyBibGFjayArIGhpc3AgKyBtYXJyaWVkICsgbm9kZWdyZWUgKyByZTc1LCAKICAgICAgICAgICAgICAgIGRhdGEgPSBOU1dfRGF0YV9MYWxvbmRlX2NsZWFuZWQsIAogICAgICAgICAgICAgICAgZmFtaWx5ID0gYmlub21pYWwpCgojIEV4dHJhY3QgcHJvcGVuc2l0eSBzY29yZXMKcHJvcGVuc2l0eV9zY29yZXMgPC0gcHJlZGljdChwc19tb2RlbCwgdHlwZSA9ICJyZXNwb25zZSIpCgojIEFkZCBwcm9wZW5zaXR5IHNjb3JlcyB0byB0aGUgZGF0YXNldApOU1dfRGF0YV9MYWxvbmRlX2NsZWFuZWQkcHJvcGVuc2l0eV9zY29yZXMgPC0gcHJvcGVuc2l0eV9zY29yZXMKCiMgRGVmaW5lIHdlaWdodHMgZm9yIGVhY2ggb2JzZXJ2YXRpb24gYmFzZWQgb24gcHJvcGVuc2l0eSBzY29yZXMKd2VpZ2h0cyA8LSBpZmVsc2UoTlNXX0RhdGFfTGFsb25kZV9jbGVhbmVkJHRyZWF0ZWQgPT0gMSwgMSAvIHByb3BlbnNpdHlfc2NvcmVzLCAxIC8gKDEgLSBwcm9wZW5zaXR5X3Njb3JlcykpCgojIFBlcmZvcm0gd2VpZ2h0ZWQgcmVncmVzc2lvbiB0byBlc3RpbWF0ZSB0cmVhdG1lbnQgZWZmZWN0CndlaWdodGVkX2xtIDwtIGxtKHJlNzggfiB0cmVhdGVkLCBkYXRhID0gTlNXX0RhdGFfTGFsb25kZV9jbGVhbmVkLCB3ZWlnaHRzID0gd2VpZ2h0cykKCiMgQ29udmVydCByZWdyZXNzaW9uIHN1bW1hcnkgdG8gTGFUZVggdGFibGUKcmVncmVzc2lvbl90YWJsZSA8LSB4dGFibGUod2VpZ2h0ZWRfbG0pCgojIFByaW50IHRoZSBMYVRlWCBjb2RlIGZvciB0aGUgdGFibGUKcHJpbnQocmVncmVzc2lvbl90YWJsZSwgaW5jbHVkZS5yb3duYW1lcyA9IEZBTFNFKQoKYGBgCgoKTGV0J3MgY2hlY2sgb3VyIGN1cnJlbnQgZGF0YWJhc2UKYGBge3J9Ck5TV19EYXRhX0xhbG9uZGVfY2xlYW5lZApgYGAKCiMgTm93IGxldCdzIGNvbmR1Y3Qgb3VyIE1MIHJlZ3Jlc3Npb24KCldlIGhhdmUgcmU3NCwgcmU3NSBhbmQgcmU3OCBhcyB0aGUgcGVyaW9kcywgd2UgaGF2ZSB0aHJlZSBwZXJpb2RzLiBGb3IgdGhlIHRyZWF0bWVudCBpbiByZTc0IGFuZCByZTc1IHRoZXJlIHdhcyBubyB0cmVhdG1lbnQsIHNvIGl0IGlzIGJhc2ljYWxseSAwLCBhbmQgZm9yIHJlNzggd2UgdXNlIHRyZWF0ZWQgYXMgdmFsdWVzLiBUaGUgb3RoZXIgY292YXJpYXRlcyB3ZSB3aWxsIGtlZXAgZXhhY3RseSB3aXRoIHRoZSBzYW1lIHZhbHVlcyBleGNlcHQgZm9yIFthZ2VdIHdoaWNoIHdlIHdpbGwgYmUgaW5jcmVhc2luZyBldmVyeSB5ZWFyLCB0YWtpbmcgdGhlIGFnZSBhcyB0aGUgYWdlIGZvciB0aGUgc3RhcnRpbmcgcGVyaW9kIHJlNzUuIFdlIHdpbGwgYmUgb25seSB1c2luZyBwZXJpb2RzIDc1IGFuZCA3OC4KCmBgYHtyfQojIENyZWF0ZSBhIGpvaW50IGRhdGFmcmFtZQpuc3cuZGYgPC0gZGF0YS5mcmFtZSgKICAjcmU3NCA9IE5TV19EYXRhX0xhbG9uZGVfY2xlYW5lZCRyZTc0LAogIHJlNzUgPSBOU1dfRGF0YV9MYWxvbmRlX2NsZWFuZWQkcmU3NSwKICByZTc4ID0gTlNXX0RhdGFfTGFsb25kZV9jbGVhbmVkJHJlNzgsCiAgI3RyZWF0ZWQ3NCA9IHJlcCgwLCBsZW5ndGgoTlNXX0RhdGFfTGFsb25kZV9jbGVhbmVkJHRyZWF0ZWQpKSwKICB0cmVhdGVkNzUgPSByZXAoMCwgbGVuZ3RoKE5TV19EYXRhX0xhbG9uZGVfY2xlYW5lZCR0cmVhdGVkKSksCiAgdHJlYXRlZDc4ID0gTlNXX0RhdGFfTGFsb25kZV9jbGVhbmVkJHRyZWF0ZWQKKQoKIyBEZWZpbmluZyB0aGUgQ292YXJpYXRlcyAKZm9yIChpIGluIGMoNzUsIDc4KSkgewogIHZhcmlhYmxlcyA8LSBjKCJlZHVjIiwgImJsYWNrIiwgIm1hcnJpZWQiLCAibm9kZWdyZWUiLCAiaGlzcCIpCiAgCiAgZm9yICh2YXIgaW4gdmFyaWFibGVzKSB7CiAgICB2YXJpYWJsZSA8LSBwYXN0ZSh2YXIsIGksIHNlcCA9ICIiKQogICAgbnN3LmRmW1t2YXJpYWJsZV1dIDwtIE5TV19EYXRhX0xhbG9uZGVfY2xlYW5lZFtbdmFyXV0KICB9Cn0KCiMgT25lIGxhc3QgY292YXJpYXRlICJhZ2UiCm5zdy5kZiRhZ2U3NSA8LSBOU1dfRGF0YV9MYWxvbmRlX2NsZWFuZWQkYWdlCm5zdy5kZiRhZ2U3OCA8LSBuc3cuZGYkYWdlNzUgKyAzCgojIFByb3BlbnNpdHkgc2NvcmVzCm5zdy5kZiRwcm9wZW5zaXR5X3Njb3Jlczc0IDwtIE5TV19EYXRhX0xhbG9uZGVfY2xlYW5lZCRwcm9wZW5zaXR5X3Njb3Jlcwpuc3cuZGYkcHJvcGVuc2l0eV9zY29yZXM3OCA8LSBOU1dfRGF0YV9MYWxvbmRlX2NsZWFuZWQkcHJvcGVuc2l0eV9zY29yZXMKI25zdy5kZiRwcm9wZW5zaXR5X3Njb3JlcyA8LSBOU1dfRGF0YV9MYWxvbmRlX2NsZWFuZWQkcHJvcGVuc2l0eV9zY29yZXMKCiMgSnVzdCBmb3IgdGhlIHJlYWwgZWFybmluZyBvZyAxOTc1Cm5zdy5kZiRSRTc1IDwtIE5TV19EYXRhX0xhbG9uZGVfY2xlYW5lZCRyZTc1Cm5zdy5kZiRSRTc4IDwtIE5TV19EYXRhX0xhbG9uZGVfY2xlYW5lZCRyZTc1CgojIERpc3BsYXkgdGhlIHJlc3VsdGluZyBkYXRhIGZyYW1lCm5zdy5kZgpgYGAKCgpOb3cgdGhhdCB3ZSBoYXZlIG91ciBkYXRhZnJhbWUsIGxldCdzIHJlc2hhcGUgb3VyIE1MIGZ1bmN0aW9uIHNvIGl0IGNhbiB3b3JrIHdpdGggdGhpcyBuZXcgZGF0YWZyYW1lLCBhbmQgd2l0aCBhbnkgZGF0YWZyYW1lLgpgYGB7cn0KQVRUX01MX2dlbmVyYXRvcl9BRFZBTkNFRF9WRiA8LSBmdW5jdGlvbihNeURhdGEsIFhfdmFyaWFibGVzX3BlcmlvZCwgeV92YXJpYWJsZV9wZXJpb2QsIGRfdmFyaWFibGVfcGVyaW9kLCBDVl9udW1fZm9sZHMsIHN0YXJ0aW5nX3Rlc3RfcGVyaW9kLCBlbmRpbmdfdGVzdF9wZXJpb2QsIG1vZGVscywgbW9kZWxzX25hbWVzKXsKICAKIyBNeURhdGEgPSBuc3cuZGYKIyBYX3ZhcmlhYmxlc19wZXJpb2QgPSBjKCdhZ2UnLCAnZWR1YycsICdibGFjaycsICdoaXNwJywgJ21hcnJpZWQnLCAnbm9kZWdyZWUnLCAncmUnKQojIHlfdmFyaWFibGVfcGVyaW9kID0gInJlIgojIGRfdmFyaWFibGVfcGVyaW9kID0gInRyZWF0ZWQiICN0cmVhdGVtZW50CiMgQ1ZfbnVtX2ZvbGRzID0gMTAKIyBzdGFydGluZ190ZXN0X3BlcmlvZCA9IDc4CiMgZW5kaW5nX3Rlc3RfcGVyaW9kID0gNzgKIyBtb2RlbHMgPC0gYygiU0wuZ2xtbmV0IiwgIlNMLnJhbmRvbUZvcmVzdCIsICJTTC54Z2Jvb3N0IiwgIlNMLmtlcm5lbEtubiIpCiMgbW9kZWxzX25hbWVzIDwtIGMoIkxBU1NPIiwgIlJGIiwgIlhnQiIsICJLZXJuZWxLbm4iKQoKIyBUaGlzIHZlY3RvciB3aWxsIHN0b3JlIG15IGRlbnNpdGllcwpkZW5zaXRpZXNfbGlzdCA8LSBsaXN0KCkKCiMgVG8gc3RvcmUgdGhlIHkgZGVuc2l0aWVzCmRlbnNpdGllc195IDwtIGxpc3QoKQoKIyBEZWZpbmUgdGhlIG1vZGVsIG5hbWVzIGFjdHVhbCB2YWx1ZQptb2RlbHNfbmFtZXNfYWN0IDwtIGMobW9kZWxzX25hbWVzLCAiSm9pbnRNIikKCiMgRGVmaW5lIGxpc3RzCk1BRSA8LSBsaXN0KCkKTVNFIDwtIGxpc3QoKQpSMiA8LSBsaXN0KCkKQVRUIDwtIGxpc3QoKQoKIyBDb21wbGV0ZSBkYXRhIGZvciBwZXJpb2RzIDMgLSA1Cgpmb3IgKGkgaW4gc3RhcnRpbmdfdGVzdF9wZXJpb2Q6ZW5kaW5nX3Rlc3RfcGVyaW9kKXsKICAKICAjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiAgIyBDcmVhdGUgdmFyaWFibGUgbmFtZXMgYmFzZWQgb24gdGhlIGxvb3AgaW5kZXgKICBkX3ByZWZpeCA8LSBwYXN0ZShkX3ZhcmlhYmxlX3BlcmlvZCwgaSwgc2VwID0gIiIpICMgcmV0cmlldmVzIHRoZSB2YXJpYWJsZQogIHlfcHJlZml4IDwtIHBhc3RlKHlfdmFyaWFibGVfcGVyaW9kLCBpLCBzZXAgPSAiIikgIyByZXRyaWV2ZXMgdGhlIHZhcmlhYmxlCiAgRGF0YV9jb21wbGV0ZVhfcHJlZml4IDwtIHBhc3RlKCJEYXRhX2NvbXBsZXRlX1h0IiwgaSwgc2VwID0gIiIpCiAgRGF0YV9jb21wbGV0ZVlfcHJlZml4IDwtIHBhc3RlKCJEYXRhX2NvbXBsZXRlX1l0IiwgaSwgc2VwID0gIiIpCgogICMgQ29tcGxldGUgdGhlIG9uZSBmb3IgWCwgbm93IHdlIHRvIGdldCB0aGUgWHMKICB4X3ZhcmlhYmxlcyA8LSBjKCkgIyB0aGlzIG9uZSB3aWxsIHN0b3JlIGFsbCBteSB4dmFyaWFibGVzIHRoYXQgSSBuZWVkCiAgZm9yICh4IGluIHNlcV9hbG9uZyhYX3ZhcmlhYmxlc19wZXJpb2QpKSB7CiAgICAKICAgIHhfcHJlZml4IDwtIHBhc3RlKFhfdmFyaWFibGVzX3BlcmlvZFt4XSwgaSwgc2VwID0gIiIpCiAgICB4X3ZhcmlhYmxlcyA8LSBjKHhfdmFyaWFibGVzLCB4X3ByZWZpeCkKICAgIAogIH0KCiAgIyBTdWJzZXQgdGhlIGRhdGEgYmFzZWQgb24gdGhlIGNvbnN0cnVjdGVkIHZhcmlhYmxlIG5hbWVzCiAgc3Vic2V0X2RhdGFfeCA8LSBzdWJzZXQoTXlEYXRhLCBzZWxlY3QgPSBjKGRfcHJlZml4LCB4X3ZhcmlhYmxlcykpCiAgYXNzaWduKERhdGFfY29tcGxldGVYX3ByZWZpeCwgYXMuZGF0YS5mcmFtZShzdWJzZXRfZGF0YV94KSkgIyBYIGFzIGRhdGFmcmFtZQoKICAjIFN1YnNldCBhbmQgYXNzaWduIFkKICBhc3NpZ24oRGF0YV9jb21wbGV0ZVlfcHJlZml4LCBNeURhdGFbW3lfcHJlZml4XV0pICMgWQoKICAjIE5vdyBsZXQncyBnZXQgdGhlIGFjdHVhbCB2YWx1ZXMgb2YgRGF0YV9jb21wbGV0ZVhfcHJlZml4IGFuZCBEYXRhX2NvbXBsZXRlWV9wcmVmaXggZm9yIGxhdGVyIHVzYWdlCiAgRGF0YV9jb21wbGV0ZVhfYWN0dWFsIDwtIGdldChEYXRhX2NvbXBsZXRlWF9wcmVmaXgpCiAgRGF0YV9jb21wbGV0ZVlfYWN0dWFsIDwtIGdldChEYXRhX2NvbXBsZXRlWV9wcmVmaXgpCgogICMgTGV0J3MgYWxzbyBnZXQgdGhlIGRlbnNpdHkgZm8gQWN0dWFsIFkganVzdCBmb3IgbGF0ZXIgLS0tLS0KCiAgIyBDcmVhdGUgdGhlIHZhcmlhYmxlIGZvciB0aGUgZGVuc2l0eQogIFlfRGVuc2l0eV9Db21wbGV0ZSA8LSBwYXN0ZSgiRGVuc2l0eV8iLCBEYXRhX2NvbXBsZXRlWV9wcmVmaXgsIHNlcCA9ICIiKQoKICAjIEFzc2lnbiB0aGUgdmFsdWVzIG9mIHRoZSB2YXJpYWJsZXMKICBhc3NpZ24oWV9EZW5zaXR5X0NvbXBsZXRlLCBkZW5zaXR5KERhdGFfY29tcGxldGVZX2FjdHVhbCkpCgogICMgU3RvcmUgdGhlIHZhbHVlcyBmb3IgdXNhZ2UgaW5zaWRlIHRoZSBsb29wIG9mIHRoZSBZIGRlbnNpdHkKICBZX2RlbnNpdHkgPC0gZ2V0KFlfRGVuc2l0eV9Db21wbGV0ZSkKICAKICAjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAKICAKICAjIFRSQUlOIERBVEEgRk9SIEFMTCBQRVJJT0RTLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAKICAjIERhdGEgdG8gVHJhaW4KICBEYXRhX3RvVHJhaW5fcHJlZml4IDwtIHBhc3RlKCJEYXRhX3RvVHJhaW5fdCIsIGksIHNlcCA9ICIiKQogIAogICMgQ3JlYXRlIHZhcmlhYmxlIG5hbWVzIGJhc2VkIG9uIHRoZSBsb29wIGluZGV4CiAgVHJhaW5feF9wcmVmaXggPC0gcGFzdGUoIlRyYWluX3hfdCIsIGksIHNlcCA9ICIiKQogIFRyYWluX3lfcHJlZml4IDwtIHBhc3RlKCJUcmFpbl95X3QiLCBpLCBzZXAgPSAiIikKICAKICAjIFN1YnNldCB0aGUgZGF0YSBiYXNlZCBvbiB0aGUgY29uc3RydWN0ZWQgdmFyaWFibGUgbmFtZXMKICBEYXRhX3RvVHJhaW5fc3Vic2V0IDwtIHN1YnNldChNeURhdGEsIE15RGF0YVtbZF9wcmVmaXhdXSA9PSAwKQogIGFzc2lnbihEYXRhX3RvVHJhaW5fcHJlZml4LCBEYXRhX3RvVHJhaW5fc3Vic2V0KSAjIERhdGEgdG8gdHJhaW4KICBhc3NpZ24oVHJhaW5feF9wcmVmaXgsIGFzLmRhdGEuZnJhbWUoc3Vic2V0KERhdGFfdG9UcmFpbl9zdWJzZXQsIHNlbGVjdCA9IGMoZF9wcmVmaXgsIHhfdmFyaWFibGVzKSkpKSAjIFgKICBhc3NpZ24oVHJhaW5feV9wcmVmaXgsIERhdGFfdG9UcmFpbl9zdWJzZXRbW3lfcHJlZml4XV0pICMgWQogIAogICMgSE9MRCBEQVRBIEZPUiBBTEwgUEVSSU9EUy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogIAogICMgRGF0YSB0byBUcmFpbgogIERhdGFfdG9Ib2xkX3ByZWZpeCA8LSBwYXN0ZSgiRGF0YV90b0hvbGRfdCIsIGksIHNlcCA9ICIiKQogIAogICMgQ3JlYXRlIHZhcmlhYmxlIG5hbWVzIGJhc2VkIG9uIHRoZSBsb29wIGluZGV4CiAgSG9sZF94X3ByZWZpeCA8LSBwYXN0ZSgiSG9sZF94X3QiLCBpLCBzZXAgPSAiIikKICBIb2xkX3lfcHJlZml4IDwtIHBhc3RlKCJIb2xkX3lfdCIsIGksIHNlcCA9ICIiKQogIAogICMgU3Vic2V0IHRoZSBkYXRhIGJhc2VkIG9uIHRoZSBjb25zdHJ1Y3RlZCB2YXJpYWJsZSBuYW1lcwogIERhdGFfdG9Ib2xkX3N1YnNldCA8LSBzdWJzZXQoTXlEYXRhLCBNeURhdGFbW2RfcHJlZml4XV0gPT0gMSkKICBhc3NpZ24oRGF0YV90b0hvbGRfcHJlZml4LCBEYXRhX3RvSG9sZF9zdWJzZXQpICMgRGF0YSB0byBob2xkCiAgYXNzaWduKEhvbGRfeF9wcmVmaXgsIGFzLmRhdGEuZnJhbWUoc3Vic2V0KERhdGFfdG9Ib2xkX3N1YnNldCwgc2VsZWN0ID0gYyhkX3ByZWZpeCwgeF92YXJpYWJsZXMpKSkpICMgWAogIGFzc2lnbihIb2xkX3lfcHJlZml4LCBEYXRhX3RvSG9sZF9zdWJzZXRbW3lfcHJlZml4XV0pICMgWQogIAogICMgTEVUJ1MgVVNFIE9VUiBNQUNISU5FIExFQVJOSU5HIE1PREVMUyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogIAogICMjIERlZmluZSB0aGUgbnVtYmVyIG9mIHN1YmRhdGEgc3BsaXRzIGZvciB0aGUgQ3Jvc3MtVmFsaWRhdGlvbgogIGNvbnRyb2wgPC0gU3VwZXJMZWFybmVyLkNWLmNvbnRyb2woViA9IENWX251bV9mb2xkcykKCiAgICMgRGVmaW5lIHRoZSB2ZWN0b3IgdGhhdCB3aWxsIHN0b3JlIG15IG1vZGVscwogIG1vZGVsc191c2UgPC0gYygpICMgZW1wdHkgYnkgbm93CiAgCiAgIyBUaGVuIHRoZSBsb29wIAogIGZvciAoaiBpbiBzZXFfYWxvbmcobW9kZWxzKSkgewogICAgCiAgICAgICMgQ3JlYXRlIHRoZSB2YXJpYWJsZXMgbmFtZXMKICAgICAgbW9kZWxfbmFtZV9wcmVmaXggPC0gcGFzdGUobW9kZWxzX25hbWVzW2pdLCAiX3QiLCBpLCBzZXAgPSAiIikKCiAgICAgICMgU2V0IHRoZSBzZWVkCiAgICAgIHNldC5zZWVkKDEpCiAgICAgIAogICAgICAjIFVzZSB0aGUgbW9kZWwgbmFtZSBpbiB0aGUgU3VwZXJMZWFybmVyIGZ1bmN0aW9uCiAgICAgIGFzc2lnbihtb2RlbF9uYW1lX3ByZWZpeCwgU3VwZXJMZWFybmVyKFkgPSBnZXQoVHJhaW5feV9wcmVmaXgpLCBYID0gZ2V0KFRyYWluX3hfcHJlZml4KSwgZmFtaWx5ID0gZ2F1c3NpYW4oKSwgU0wubGlicmFyeSA9IG1vZGVsc1tqXSwgY3ZDb250cm9sID0gY29udHJvbCkpCiAgICAgIAogICAgICAjIEFkZCBlbGVtZW50cyB0b3AgdGhlIG1vZGVsc191c2UKICAgICAgbW9kZWxzX3VzZSA8LSBjKG1vZGVsc191c2UsIG1vZGVsX25hbWVfcHJlZml4KQogIH0KICAKICAjIERlZmluaW5nIHRoZSBqb2ludCBtb2RlbAogIEpvaW50TV9wcmVmaXggPC0gcGFzdGUoIkpvaW50TV90IiwgaSwgc2VwID0gIiIpCiAgICMgU2V0IHRoZSBzZWVkCiAgc2V0LnNlZWQoMSkKICAjIEpvaW50IG1vZGVsCiAgYXNzaWduKEpvaW50TV9wcmVmaXgsIFN1cGVyTGVhcm5lcihZID0gZ2V0KFRyYWluX3lfcHJlZml4KSwgWCA9IGdldChUcmFpbl94X3ByZWZpeCksIGZhbWlseSA9IGdhdXNzaWFuKCksIFNMLmxpYnJhcnkgPSBtb2RlbHMsIGN2Q29udHJvbCA9IGNvbnRyb2wpKQogIAogICMgQWRkIGxhc3QgZWxlbWVudCB0byBtb2RlbHNfdXNlCiAgbW9kZWxzX3VzZSA8LSBjKG1vZGVsc191c2UsIEpvaW50TV9wcmVmaXgpCiAgCiAgIyBVTlRJTCBIRVJFIEFMTCBGSU5FIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgCiAgIyBQUkVESUNUSU9OUyBUSU1FIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAKICAjIEluaXRpYWxpemUgdGhlIGlubmVyIGxpc3QgZm9yIG1vZGVscyBmb3IgdGhlIGN1cnJlbnQgcGVyaW9kCiAgTUFFX3BlcmlvZCA8LSBsaXN0KCkKICBNU0VfcGVyaW9kIDwtIGxpc3QoKQogIFIyX3BlcmlvZCA8LSBsaXN0KCkKICBBVFRfcGVyaW9kIDwtIGxpc3QoKQoKICBmb3IgKG1vZGVsIGluIG1vZGVsc191c2UpIHsKICAgIAogICAgIyBFeHRyYWN0aW5nIHRoZSBhY3R1YWwgb2JqZWN0IChmb3IgYm90aCBQUkUtIGFuZCBQT1NULSB0cmVhdG1lbnQgcHJlZGljdGlvbnMpCiAgICBtb2RlbF9vYmogPC0gZ2V0KG1vZGVsKQogICAgCiAgICAjIFBSRS1UUkVBVE1FTlQgUFJFRElDVElPTlMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAKICAgICMgQ3JlYXRlIHZhcmlhYmxlIG5hbWVzIGJhc2VkIG9uIHRoZSBsb29wIGluZGV4CiAgICBpbl9wcmVkc19tb2RlbF9wcmVfcHJlZml4IDwtIHBhc3RlKCJpbl9wcmVkc18iLCBtb2RlbCwgIl9wcmUiLCBzZXAgPSAiIikKICAgIGN2X3ByZWRzX21vZGVsX3ByZV9wcmVmaXggPC0gcGFzdGUoImluX3ByZWRzXyIsIG1vZGVsLCAiX3ByZSIsIHNlcCA9ICIiKQogICAgZGF0YV9tb2RlbF9wcmVfcHJlZml4IDwtIHBhc3RlKCJkYXRhXyIsIG1vZGVsLCAiX3ByZSIsIHNlcCA9ICIiKQogIAogICAgIyBBc3NpZ24gdGhlIHZhbHVlcwogICAgYXNzaWduKGluX3ByZWRzX21vZGVsX3ByZV9wcmVmaXgsIGFzLmRhdGEuZnJhbWUobW9kZWxfb2JqJGxpYnJhcnkucHJlZGljdCkpCiAgICBhc3NpZ24oY3ZfcHJlZHNfbW9kZWxfcHJlX3ByZWZpeCwgYXMuZGF0YS5mcmFtZShtb2RlbF9vYmokWikpCiAgCiAgICAjIENoYW5nZSB0aGUgY29sdW1ucyBuYW1lcwogICAgb3JpZ2luYWxfaW5fcHJlZHNfbW9kZWwgPC0gZ2V0KGluX3ByZWRzX21vZGVsX3ByZV9wcmVmaXgpCiAgICBjb2xuYW1lcyhvcmlnaW5hbF9pbl9wcmVkc19tb2RlbCkgPC0gc3ByaW50ZignJXNfaW5fJXMnLCBtb2RlbCwgY29sbmFtZXMob3JpZ2luYWxfaW5fcHJlZHNfbW9kZWwpKQogICAgYXNzaWduKGluX3ByZWRzX21vZGVsX3ByZV9wcmVmaXgsIG9yaWdpbmFsX2luX3ByZWRzX21vZGVsKQoKICAgIG9yaWdpbmFsX2N2X3ByZWRzX21vZGVsIDwtIGdldChjdl9wcmVkc19tb2RlbF9wcmVfcHJlZml4KQogICAgY29sbmFtZXMob3JpZ2luYWxfY3ZfcHJlZHNfbW9kZWwpIDwtIHNwcmludGYoJyVzX2N2XyVzJywgbW9kZWwsIGNvbG5hbWVzKG9yaWdpbmFsX2N2X3ByZWRzX21vZGVsKSkKICAgIGFzc2lnbihjdl9wcmVkc19tb2RlbF9wcmVfcHJlZml4LCBvcmlnaW5hbF9jdl9wcmVkc19tb2RlbCkKICAKICAgICMgSm9pbmluZyBib3RoIHZhcmlhYmxlcyBpbnRvIGEgZGF0YWZyYW1lCiAgICBhc3NpZ24oZGF0YV9tb2RlbF9wcmVfcHJlZml4LCBjYmluZChnZXQoaW5fcHJlZHNfbW9kZWxfcHJlX3ByZWZpeCksIGdldChjdl9wcmVkc19tb2RlbF9wcmVfcHJlZml4KSkpCiAgICAKICAgIAogICAgIyBMRVQnUyBSRUNPVkVSIFRIRSBDUk9TU1ZBTElEQVRFRCBFUlJPUlMtLS0tLQogICAgCiAgICAjIENyZWF0ZSB2YXJpYWJsZSBuYW1lcyBiYXNlZCBvbiB0aGUgbG9vcCBpbmRleAogICAgQ1ZfbmFtZXMgPC0gcGFzdGUoIkNWX0VfIiwgbW9kZWwsIHNlcCA9ICIiKQogICAgCiAgICAjIEFzc2lnbiB0aGUgdmFsdWVzIAogICAgYXNzaWduKENWX25hbWVzLCBnZXQoVHJhaW5feV9wcmVmaXgpIC0gZ2V0KGN2X3ByZWRzX21vZGVsX3ByZV9wcmVmaXgpKQogICAgCiAgICAjIFBPU1QtVFJFQVRNRU5UIFBSRURJQ1RJT05TLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogICAgCiAgICAjIENyZWF0ZSB2YXJpYWJsZSBuYW1lcyBiYXNlZCBvbiB0aGUgbG9vcCBpbmRleAogICAgcHJlZHNfbW9kZWxfcG9zdF9wcmVmaXggPC0gcGFzdGUoInByZWRNb2RlbF8iLCBtb2RlbCwgIl9wb3N0Iiwgc2VwID0gIiIpCiAgICBkYXRhX21vZGVsX3Bvc3RfcHJlZml4IDwtIHBhc3RlKCJkYXRhXyIsIG1vZGVsLCAiX3Bvc3QiLCBzZXAgPSAiIikKICAgIAogICAgIyBBc3NpZ24gdGhlIHZhbHVlcwogICAgYXNzaWduKHByZWRzX21vZGVsX3Bvc3RfcHJlZml4LCBwcmVkaWN0KG1vZGVsX29iaiwgRGF0YV9jb21wbGV0ZVhfYWN0dWFsLCBvbmx5U0wgPSBUKSkKICAgIAogICAgIyBOb3cgZ2V0IHRoZSBwcmVkc19tb2RlbF9wb3N0X3ByZWZpeCBhY3R1YWwgdmFsdWUKICAgIHByZWRzX21vZGVsX29iaiA8LSBnZXQocHJlZHNfbW9kZWxfcG9zdF9wcmVmaXgpICMgQWxzbyBuZWVkZWQgZm9yIHRoZSBzdWJzZXF1ZW50IHN0ZXBzCiAgICAKICAgICMgQXNzaWduIHRoZSB2YWx1ZXMgbm93CiAgICBhc3NpZ24oZGF0YV9tb2RlbF9wb3N0X3ByZWZpeCwgYXMuZGF0YS5mcmFtZShwcmVkc19tb2RlbF9vYmokcHJlZCkpCiAgICAKICAgICMgQ2hhbmdlIHRoZSBjb2x1bW5zIG5hbWVzCiAgICBvcmlnaW5hbF9kYXRhX21vZGVsX3Bvc3QgPC0gZ2V0KGRhdGFfbW9kZWxfcG9zdF9wcmVmaXgpCiAgICBjb2xuYW1lcyhvcmlnaW5hbF9kYXRhX21vZGVsX3Bvc3QpIDwtIHNwcmludGYoJyVzX2luXyVzJywgbW9kZWwsIGNvbG5hbWVzKG9yaWdpbmFsX2RhdGFfbW9kZWxfcG9zdCkpCiAgICBhc3NpZ24oZGF0YV9tb2RlbF9wb3N0X3ByZWZpeCwgb3JpZ2luYWxfZGF0YV9tb2RlbF9wb3N0KQogICAgCiAgICAjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgICAKICAgICMgTEVUJ1MgR0VUIFRIRSBERU5TSVRJRVMgRk9SIFBMT1RUSU5HLS0tLS0tCiAgICAKICAgICMgQ3JlYXRlIHZhcmlhYmxlIG5hbWVzIGJhc2VkIG9uIHRoZSBsb29wIGluZGV4CiAgICBEZW5zaXR5X25hbWUgPC0gcGFzdGUoImRlbnNpdHlfIiwgbW9kZWwsIHNlcCA9ICIiKQogICAgCiAgICAjIEFzc2lnbiB0aGUgdmFsdWVzCiAgICAjIGFzc2lnbihEZW5zaXR5X25hbWUsIGRhdGFfbW9kZWxfcG9zdF9wcmVmaXhbLCAxXSkgIyBUaGlzIHdpbGwgcmV0dXJuIHRoZSB2YWx1ZSBhcyBhIHZlY3RvcgogICAgYXNzaWduKERlbnNpdHlfbmFtZSwgZGVuc2l0eShwcmVkc19tb2RlbF9vYmokcHJlZFssIDFdKSkgIyBUaGlzIHdpbGwgcmV0dXJuIHRoZSB2YWx1ZSBhcyBhIHZlY3RvciwgdXNpbmcgcHJlZHNfbW9kZWxfb2JqIE9CSkVDVAogICAgCiAgICAjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgICAKICAgICMgTEVUJ1MgR0VUIFRIRSBNQUUsIE1TRSAmIFIyCiAgICAKICAgICMgV2Ugd2lsbCB1c2UsIE1BRSAobWVhbiBhYnNvbHV0ZSBlcnJvciksIE1TRSAobWVhbiBzcXVhcmVkIGVycm9yLCB0aGlzIG9uZSBtYWtlcyBzdXJlIHRvIGRlYWwgd2l0aCBuZWdhdGl2ZSBkaXN0YW5jZXMpLCBSMiAoUi1zcXVhcmVkKQoKICAgICMgQ29tcHV0ZSBNQUUsIE1TRSAmIFIyIGZvciB0aGUgY3VycmVudCBtb2RlbCBhbmQgcGVyaW9kCiAgICBNQUVfdmFsdWUgPC0gbWFlKERhdGFfY29tcGxldGVZX2FjdHVhbCwgYXMudmVjdG9yKHVubGlzdChnZXQoZGF0YV9tb2RlbF9wb3N0X3ByZWZpeCkpKSkKICAgIE1TRV92YWx1ZSA8LSBtc2UoRGF0YV9jb21wbGV0ZVlfYWN0dWFsLCBhcy52ZWN0b3IodW5saXN0KGdldChkYXRhX21vZGVsX3Bvc3RfcHJlZml4KSkpKQogICAgUjJfdmFsdWUgPC0gUjIoRGF0YV9jb21wbGV0ZVlfYWN0dWFsLCBhcy52ZWN0b3IodW5saXN0KGdldChkYXRhX21vZGVsX3Bvc3RfcHJlZml4KSkpKQoKICAgICMgU3RvcmUgdGhlIE1BRSwgTVNFLCBSMiB2YWx1ZSBpbiB0aGUgcmVzcGVjdGl2ZSBsaXN0IGJhc2VkIG9uIHRoZSBtb2RlbCB0eXBlIFRIUyBGT1IgRUFDSAogICAgCiAgICAjIFN0b3JlIHRoZSBNQUUgdmFsdWUgaW4gdGhlIGlubmVyIGxpc3QgZm9yIHRoZSBjdXJyZW50IG1vZGVsCiAgICBNQUVfcGVyaW9kW1ttb2RlbF1dIDwtIE1BRV92YWx1ZQogICAgCiAgICAjIFN0b3JlIHRoZSBNQUUgdmFsdWUgaW4gdGhlIGlubmVyIGxpc3QgZm9yIHRoZSBjdXJyZW50IG1vZGVsCiAgICBNU0VfcGVyaW9kW1ttb2RlbF1dIDwtIE1TRV92YWx1ZQogICAgCiAgICAjIFN0b3JlIHRoZSBNQUUgdmFsdWUgaW4gdGhlIGlubmVyIGxpc3QgZm9yIHRoZSBjdXJyZW50IG1vZGVsCiAgICBSMl9wZXJpb2RbW21vZGVsXV0gPC0gUjJfdmFsdWUKCiAgICAjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgICAKICAgICMgTEVUJ1MgR0VUIFRIRSBESUZGRVJFTkNFUyBUSEFUIFdFIFdJTEwgTkVFRCBUTyBSRUNPVkVSIFRIRSBBVFQKICAgIAogICAgIyBDcmVhdGUgdmFyaWFibGUgbmFtZXMgYmFzZWQgb24gdGhlIGxvb3AgaW5kZXgKICAgIERpZmZlcmVuY2VzIDwtIHBhc3RlKCJEaWZmZXJlbmNlXyIsIG1vZGVsLCBzZXAgPSAiIikKICAgIAogICAgIyBBc3NpZ24gdGhlIHZhbHVlcyBub3cKICAgICNhc3NpZ24oRGlmZmVyZW5jZXMsIGFzLnZlY3Rvcih1bmxpc3QoZ2V0KGRhdGFfbW9kZWxfcG9zdF9wcmVmaXgpKSkgLSBEYXRhX2NvbXBsZXRlWV9hY3R1YWwpCiAgICBhc3NpZ24oRGlmZmVyZW5jZXMsIGFzLnZlY3RvcihEYXRhX2NvbXBsZXRlWV9hY3R1YWwgLSB1bmxpc3QoZ2V0KGRhdGFfbW9kZWxfcG9zdF9wcmVmaXgpKSkpCiAgICAKICAgICMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAgIAogICAgIyBMRVQnUyBHRVQgQVRUIFBFUiBQRVJJT0QgUEVSIE1PREVMCiAgICAKICAgICMgQ3JlYXRlIHZhcmlhYmxlIG5hbWVzIGJhc2VkIG9uIHRoZSBsb29wIGluZGV4CiAgICAjIEFUVCA8LSBwYXN0ZSgiQVRUXyIsIG1vZGVsLCBzZXAgPSAiIikgIyBBQ1RVQUxMWSBOTyBORUVECiAgICAKICAgICMgQ29tcHV0ZSBBVFQgZm9yIHRoZSBjdXJyZW50IG1vZGVsIGFuZCBwZXJpb2QKICAgIEFUVF92YWx1ZSA8LSBtZWFuKGdldChwYXN0ZSgiRGlmZmVyZW5jZV8iLCBtb2RlbCwgc2VwID0gIiIpKSkKICAgIAogICAgIyBTdG9yZSB0aGUgTUFFIHZhbHVlIGluIHRoZSBpbm5lciBsaXN0IGZvciB0aGUgY3VycmVudCBtb2RlbAogICAgQVRUX3BlcmlvZFtbbW9kZWxdXSA8LSBBVFRfdmFsdWUKICAgIAogIH0KICAKICAjIE1BRSwgTVNFLCBSMiAmIEFUVCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgIyBBcHBlbmQgdGhlIGlubmVyIGxpc3QgdG8gdGhlIG91dGVyIGxpc3QgZm9yIHRoZSBjdXJyZW50IHBlcmlvZAogIE1BRVtbcGFzdGUoIlBlcmlvZCIsIGksIHNlcCA9ICJfIildXSA8LSBNQUVfcGVyaW9kCiAgTVNFW1twYXN0ZSgiUGVyaW9kIiwgaSwgc2VwID0gIl8iKV1dIDwtIE1TRV9wZXJpb2QKICBSMltbcGFzdGUoIlBlcmlvZCIsIGksIHNlcCA9ICJfIildXSA8LSBSMl9wZXJpb2QKICBBVFRbW3Bhc3RlKCJQZXJpb2QiLCBpLCBzZXAgPSAiXyIpXV0gPC0gQVRUX3BlcmlvZAogIAogICMgRGVuc2l0aWVzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgCiAgIyBDcmVhdGUgdmFyaWFibGUgbmFtZXMgYmFzZWQgb24gdGhlIGxvb3AgaW5kZXgKICBEYXRhX3Bsb3R0aW5nIDwtIHBhc3RlKCJUb1Bsb3REYXRhX2RlbnNpdGllc190IiwgaSwgc2VwID0gIiIpCgogICMgR2V0IHRoZSB2YWx1ZXMgb2YgdGhlIG1vZGVscyBhZ2FpbiAtIFVzaW5nIHRoZSBmYWN0IHRoYXQgd2UgaGF2ZSBhbHJlYWR5IGRlZmluZWQgb3VyIG1vZGVscyBhYm92ZSBpbiAibW9kZWxzX3VzZSIgb3V0c2lkZSB0aGUgbW9kZWwgbG9vcAogIFlfYWN0dWFsX2RlbnNpdHkgPC0gZ2V0KHBhc3RlKCJEZW5zaXR5XyIsIERhdGFfY29tcGxldGVZX3ByZWZpeCwgc2VwID0gIiIpKQogIAogICMgUGVyaW9kIGRlbnNpdGllcwogIHBlcmlvZF9kZW5zaXRpZXMgPC0gbGlzdCgpCiAgCiAgZm9yIChtIGluIHNlcV9hbG9uZyhtb2RlbHNfdXNlKSkgewogICAgCiAgICAjIERlZmluaW5nIHRoZSBuYW1lcyBvZiB0aGUgZGVuc2l0aWVzCiAgICBtb2RlbF9uYW1lIDwtIG1vZGVsc19uYW1lc19hY3RbbV0gIyBUbyBkZWZpbmUgdGhlIG5hbWUgb2YgdGhlIG1vZGVsCiAgICBwcmVmaXhfZGVuc2l0eSA8LSBwYXN0ZShtb2RlbF9uYW1lLCAiZGVuc2l0eSIsIHNlcCA9ICJfIikKICAgIAogICAgIyBEZWZpbmluZyB0aGUgdmFsdWVzIHRvIGJlIGFzc2lnbmVkCiAgICBtb2RlbF92YWx1ZXMgPC0gZ2V0KHBhc3RlKCJkZW5zaXR5XyIsIG1vZGVsc191c2VbbV0sIHNlcCA9ICIiKSkKCiAgICAjIENyZWF0ZSB2YXJpYWJsZSBuYW1lcyBkeW5hbWljYWxseQogICAgYXNzaWduKHByZWZpeF9kZW5zaXR5LCBtb2RlbF92YWx1ZXMpCiAgICAKICAgICMgU3RvcmUgdGhlIGRlbnNpdGllcwogICAgcGVyaW9kX2RlbnNpdGllc1tbcHJlZml4X2RlbnNpdHldXSA8LSBnZXQocHJlZml4X2RlbnNpdHkpCiAgICAKICB9CgogICMgTGlzdCBvZiBtb2RlbHMKICBsaXN0X21vZGVscyA8LSBjKCJZX2FjdHVhbCIsICJMQVNTTyIsICJSYW5kb20gRm9yZXN0IiwgIlhHQm9vc3QiLCAiSm9pbnRNIikKICAKICAjIFN0b3JlIG15IGRlbnNpdGllcwogIAogICMgRGVmaW5pbmcgdmFyaWFibGUgbmFtZXMgaW5zaWRlIHRoZSBsaXN0CiAgbmFtZXNfZGVuc2l0aWVzX3BlcmlvZHMgPC0gcGFzdGUoInQiLCBpLCBzZXAgPSAiIikKICBkZW5zaXRpZXNfbGlzdFtbbmFtZXNfZGVuc2l0aWVzX3BlcmlvZHNdXSA8LSBwZXJpb2RfZGVuc2l0aWVzCiAgCiAgIyBBZGRpbmcgdGhlIHZhbHVlIG9mIFkgZGVuc2l0eS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogIGRlbnNpdGllc195W1twYXN0ZSgiRGVuc2l0eV95dCIsIGksIHNlcCA9ICIiKV1dIDwtIFlfYWN0dWFsX2RlbnNpdHkKCn0KCiMgU3RhdGlzdGljcyAKCiMgQ29tYmluZSB0aGUgdmVjdG9ycyBpbnRvIGEgbGlzdApTdGF0aXRpY3MgPC0gbGlzdCgKICBBVFQgPSBBVFQsCiAgTUFFID0gTUFFLAogIE1TRSA9IE1TRSwKICBSMiA9IFIyCikKCiMgQVZFUkFHRVMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMgTm93IGRlcGVuZGluZyBvbiB0aGUgbnVtYmVyIG9mIHBlcmlvZHMgYW5kIHRoZSBudW1iZXIgb2YgbW9kZWxzIHNvIHdlIG5lZWQgdG8gZGl2aWRlIGZvciBleGFtcGVsIGlmIG1vZGVscyBhcmUKbnVtX3BlcmlvZHMgPSAoZW5kaW5nX3Rlc3RfcGVyaW9kIC0gc3RhcnRpbmdfdGVzdF9wZXJpb2QpICsgMQpudW1fbW9kZWxzID0gbGVuZ3RoKG1vZGVsc19uYW1lc19hY3QpCgojIEF2ZXJhZ2VzIHBlciBtb2RlbApTdGF0aXN0aWNfYXZlcmFnZXMgPC0gbGlzdCgpCgojIFN0YXRpc3RpY3MgbGlzdApTdGF0aXN0aWNzX2xpc3QgPC0gYygiQVRUIiwgIk1BRSIsICJNU0UiLCAiUjIiKQoKIyBMb29wIG92ZXIgU3RhdGlzdGljcyBsaXN0CmZvciAocyBpbiBTdGF0aXN0aWNzX2xpc3QpIHsKICAKICAjIExpc3QgYXZlcmFnZXMKICBBdmVyYWdlc19saXN0IDwtIGxpc3QoKQogIAogICMgTG9vcCBvdmVyIG1vZGVscwogIGZvciAobW9kIGluIG1vZGVsc19uYW1lc19hY3QpIHsKICAKICAgICMgQ3JlYXRlIHRoZSBuYW1lIG9mIHRoZSB2YXJpYWJsZQogICAgUHJlZml4X2F2ZXJhZ2UgPC0gcGFzdGUocywgbW9kLCAiYXZlcmFnZSIsIHNlcCA9ICJfIikKCiAgICAjIEluaXRpYWxpemUgbWVhbl9wZXJfbW9kZWwgZm9yIGVhY2ggbW9kZWwKICAgIG1lYW5fcGVyX21vZGVsIDwtIDAKCiAgICAjIExvb3Agb3ZlciBwZXJpb2RzCiAgICBmb3IgKGkgaW4gMTpudW1fcGVyaW9kcykgewogICAgICAjIENvbGxlY3RpbmcgdGhlIG1lYW4gZm9yIGVhY2ggbW9kZWwgZm9yIGVhY2ggcGVyaW9kCiAgICAgIHN0YXRfdmFsdWUgPC0gZ2V0KHBhc3RlKHMsIHNlcCA9ICIiKSlbW2ldXVtbd2hpY2gobW9kZWxzX25hbWVzX2FjdCA9PSBtb2QpXV0KICAgICAgbWVhbl9wZXJfbW9kZWwgPC0gbWVhbl9wZXJfbW9kZWwgKyBzdGF0X3ZhbHVlCiAgICB9CgogICAgIyBDYWxjdWxhdGUgdGhlIGF2ZXJhZ2UgYWNyb3NzIGFsbCBwZXJpb2RzIGZvciB0aGUgY3VycmVudCBtb2RlbAogICAgbWVhbl9wZXJfbW9kZWwgPC0gbWVhbl9wZXJfbW9kZWwgLyBudW1fcGVyaW9kcwoKICAgICMgU3RvcmUgdGhlIHJlc3VsdCBpbiBBdmVyYWdlc19saXN0CiAgICBBdmVyYWdlc19saXN0W1tQcmVmaXhfYXZlcmFnZV1dIDwtIG1lYW5fcGVyX21vZGVsCiAgfQogIAogICMgU3RvcmUgdGhlIHZhbHVlcwogIFN0YXRpc3RpY19hdmVyYWdlc1tbc11dIDwtIEF2ZXJhZ2VzX2xpc3QKfQoKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIEFDVFVBTCBPVVRQVVRTICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCm91dHB1dCA8LSBsaXN0KAogIEZpdG5lc3NTdGF0aXN0aWNzID0gU3RhdGl0aWNzLAogIGF2ZXJhZ2VfdmFsdWVzID0gU3RhdGlzdGljX2F2ZXJhZ2VzLAogIGRlbnNpdGllc195ID0gZGVuc2l0aWVzX3ksCiAgZGVuc2l0aWVzX01MX2xpc3QgPSBkZW5zaXRpZXNfbGlzdAopCgpyZXR1cm4ob3V0cHV0KQoKfQpgYGAKCgpJbnB1dHMKYGBge3J9Ck15RGF0YTIgPSBuc3cuZGYKWF92YXJpYWJsZXNfcGVyaW9kID0gYygnYWdlJywgJ2VkdWMnLCAnYmxhY2snLCAnaGlzcCcsICdtYXJyaWVkJywgJ25vZGVncmVlJywgIlJFIiwgJ3Byb3BlbnNpdHlfc2NvcmVzJykKI1hfdmFyaWFibGVzX3BlcmlvZCA9IGMoJ2FnZScsICdlZHVjJywgJ2JsYWNrJywgJ2hpc3AnLCAnbWFycmllZCcsICdub2RlZ3JlZScpCnlfdmFyaWFibGVfcGVyaW9kID0gInJlIgpkX3ZhcmlhYmxlX3BlcmlvZCA9ICJ0cmVhdGVkIiAjdHJlYXRlbWVudApDVl9udW1fZm9sZHMgPSAxMApzdGFydGluZ190ZXN0X3BlcmlvZDIgPSA3OAplbmRpbmdfdGVzdF9wZXJpb2QyID0gNzgKbW9kZWxzIDwtIGMoIlNMLmdsbW5ldCIsICJTTC5yYW5kb21Gb3Jlc3QiLCAiU0wueGdib29zdCIsICJTTC5rZXJuZWxLbm4iKQptb2RlbHNfbmFtZXMgPC0gYygiTEFTU08iLCAiUkYiLCAiWGdCIiwgIktlcm5lbEtubiIpCmBgYAoKUmVzdWx0cwpgYGB7cn0KTlNXLnJlc3VsdHNfTUwgPC0gQVRUX01MX2dlbmVyYXRvcl9BRFZBTkNFRF9WRihNeURhdGEyLCBYX3ZhcmlhYmxlc19wZXJpb2QsIHlfdmFyaWFibGVfcGVyaW9kLCBkX3ZhcmlhYmxlX3BlcmlvZCwgQ1ZfbnVtX2ZvbGRzLCBzdGFydGluZ190ZXN0X3BlcmlvZDIsIGVuZGluZ190ZXN0X3BlcmlvZDIsIG1vZGVscywgbW9kZWxzX25hbWVzKQpgYGAKCiMgTm93IGxldCdzIGdldCBzb21lIGdyYXBoaWNzCmBgYHtyfQojIyMjIyMgV2Ugd2lsbCBhbHNvIHVzZSB0aGUgYXZlcmFnZXMgbGlzdHMgZm9yIG91ciBwdXJwb3NlcwoKIyBBVFQKQVRUX2F2ZXJhZ2VzX25zd19NTCA8LSBkYXRhLmZyYW1lKG1hdHJpeCh1bmxpc3QoTlNXLnJlc3VsdHNfTUwkYXZlcmFnZV92YWx1ZXMkQVRUKSwgbnJvdyA9IGxlbmd0aChOU1cucmVzdWx0c19NTCRhdmVyYWdlX3ZhbHVlcyRBVFQpLCBieXJvdyA9IFRSVUUpLCByb3cubmFtZXMgPSBuYW1lcyhOU1cucmVzdWx0c19NTCRhdmVyYWdlX3ZhbHVlcyRBVFQpKQoKIyBNQUUKTUFFX2F2ZXJhZ2VzX25zd19NTCA8LSBkYXRhLmZyYW1lKG1hdHJpeCh1bmxpc3QoTlNXLnJlc3VsdHNfTUwkYXZlcmFnZV92YWx1ZXMkTUFFKSwgbnJvdyA9IGxlbmd0aChOU1cucmVzdWx0c19NTCRhdmVyYWdlX3ZhbHVlcyRNQUUpLCBieXJvdyA9IFRSVUUpLCByb3cubmFtZXMgPSBuYW1lcyhOU1cucmVzdWx0c19NTCRhdmVyYWdlX3ZhbHVlcyRNQUUpKQoKIyBNU0UKTVNFX2F2ZXJhZ2VzX25zd19NTCA8LSBkYXRhLmZyYW1lKG1hdHJpeCh1bmxpc3QoTlNXLnJlc3VsdHNfTUwkYXZlcmFnZV92YWx1ZXMkTVNFKSwgbnJvdyA9IGxlbmd0aChOU1cucmVzdWx0c19NTCRhdmVyYWdlX3ZhbHVlcyRNU0UpLCBieXJvdyA9IFRSVUUpLCByb3cubmFtZXMgPSBuYW1lcyhOU1cucmVzdWx0c19NTCRhdmVyYWdlX3ZhbHVlcyRNU0UpKQoKIyBSMgpSMl9hdmVyYWdlc19uc3dfTUwgPC0gZGF0YS5mcmFtZShtYXRyaXgodW5saXN0KE5TVy5yZXN1bHRzX01MJGF2ZXJhZ2VfdmFsdWVzJFIyKSwgbnJvdyA9IGxlbmd0aChOU1cucmVzdWx0c19NTCRhdmVyYWdlX3ZhbHVlcyRSMiksIGJ5cm93ID0gVFJVRSksIHJvdy5uYW1lcyA9IG5hbWVzKE5TVy5yZXN1bHRzX01MJGF2ZXJhZ2VfdmFsdWVzJFIyKSkKCiMgRm9yIHRoYSB0YWJsZQpUYWJsZV9uc3dfTUwgPC0gY2JpbmQoQVRUX2F2ZXJhZ2VzX25zd19NTCwgTUFFX2F2ZXJhZ2VzX25zd19NTCwgTVNFX2F2ZXJhZ2VzX25zd19NTCwgUjJfYXZlcmFnZXNfbnN3X01MKQoKIyBBZGQgY29sdW1uIG5hbWVzCmNvbG5hbWVzKFRhYmxlX25zd19NTCkgPC0gYygiQVRUIiwgIk1BRSIsICJNU0UiLCAiUjIiKSAKCiMgQWRkIHJvdyBuYW1lcwpyb3duYW1lcyhUYWJsZV9uc3dfTUwpIDwtIGMobW9kZWxzX25hbWVzLCAiSm9pbnRNIikKCiMgQ3JlYXRlIGEgY29kZSBmb3IgYSBMYVRlWCBUYWJsZQpsYXRleF9jb2RlX25zd19NTCA8LSB4dGFibGUoVGFibGVfbnN3X01MLCBjYXB0aW9uID0gIk1MIHJlc3VsdHMgcGVyIG1vZGVsIGZvciB0aGUgTlNXIERhdGEiKQoKIyBQcmludCB0aGUgTGFUZVggY29kZQpwcmludChsYXRleF9jb2RlX25zd19NTCwgaW5jbHVkZS5yb3duYW1lcyA9IFQpCmBgYAoKTGV0J3MgYWxzbyBnZXQgb3VyIGRlbnNpdGllcyBncmFwaCB0byBjaGVjayBob3cgd2VsbCBvdXIgcHJlZGljdGVkIHZhbHVlcyBmaXQgdGhlIGFjdHVhbCB2YWx1ZQpEZW5zaXRpZXMKCmBgYHtyfQpsaXN0X21vZGVscyA8LSBjKCJZX2FjdHVhbCIsIG1vZGVsc19uYW1lcywgIkpvaW50TSIpCmBgYAoKYGBge3J9CiMgVmFsdWVzIG9mIHRoZSBkZW5zaXRpZXMKVG9QbG90RGF0YV9kZW5zaXRpZXNfdDc4IDwtIGRhdGEuZnJhbWUoCiAgdmFsdWUgPSBjKE5TVy5yZXN1bHRzX01MJGRlbnNpdGllc195JERlbnNpdHlfeXQ3OCR4LCAKICAgICAgICAgICAgTlNXLnJlc3VsdHNfTUwkZGVuc2l0aWVzX01MX2xpc3QkdDc4JExBU1NPX2RlbnNpdHkkeCwgCiAgICAgICAgICAgIE5TVy5yZXN1bHRzX01MJGRlbnNpdGllc19NTF9saXN0JHQ3OCRSRl9kZW5zaXR5JHgsIAogICAgICAgICAgICBOU1cucmVzdWx0c19NTCRkZW5zaXRpZXNfTUxfbGlzdCR0NzgkWGdCX2RlbnNpdHkkeCwKICAgICAgICAgICAgTlNXLnJlc3VsdHNfTUwkZGVuc2l0aWVzX01MX2xpc3QkdDc4JEtlcm5lbEtubl9kZW5zaXR5JHgsCiAgICAgICAgICAgIE5TVy5yZXN1bHRzX01MJGRlbnNpdGllc19NTF9saXN0JHQ3OCRKb2ludE1fZGVuc2l0eSR4KSwKICBkZW5zaXR5ID0gYyhOU1cucmVzdWx0c19NTCRkZW5zaXRpZXNfeSREZW5zaXR5X3l0NzgkeSwgCiAgICAgICAgICAgIE5TVy5yZXN1bHRzX01MJGRlbnNpdGllc19NTF9saXN0JHQ3OCRMQVNTT19kZW5zaXR5JHksIAogICAgICAgICAgICBOU1cucmVzdWx0c19NTCRkZW5zaXRpZXNfTUxfbGlzdCR0NzgkUkZfZGVuc2l0eSR5LCAKICAgICAgICAgICAgTlNXLnJlc3VsdHNfTUwkZGVuc2l0aWVzX01MX2xpc3QkdDc4JFhnQl9kZW5zaXR5JHksCiAgICAgICAgICAgIE5TVy5yZXN1bHRzX01MJGRlbnNpdGllc19NTF9saXN0JHQ3OCRLZXJuZWxLbm5fZGVuc2l0eSR5LAogICAgICAgICAgICBOU1cucmVzdWx0c19NTCRkZW5zaXRpZXNfTUxfbGlzdCR0NzgkSm9pbnRNX2RlbnNpdHkkeSksCiAgbW9kZWwgPSBmYWN0b3IocmVwKGxpc3RfbW9kZWxzLCB0aW1lcyA9IHNhcHBseShsaXN0KAogICAgTlNXLnJlc3VsdHNfTUwkZGVuc2l0aWVzX3kkRGVuc2l0eV95dDc4LAogICAgTlNXLnJlc3VsdHNfTUwkZGVuc2l0aWVzX01MX2xpc3QkdDc4JExBU1NPX2RlbnNpdHksIAogICAgTlNXLnJlc3VsdHNfTUwkZGVuc2l0aWVzX01MX2xpc3QkdDc4JFJGX2RlbnNpdHksIAogICAgTlNXLnJlc3VsdHNfTUwkZGVuc2l0aWVzX01MX2xpc3QkdDc4JFhnQl9kZW5zaXR5LAogICAgTlNXLnJlc3VsdHNfTUwkZGVuc2l0aWVzX01MX2xpc3QkdDc4JEtlcm5lbEtubl9kZW5zaXR5LAogICAgTlNXLnJlc3VsdHNfTUwkZGVuc2l0aWVzX01MX2xpc3QkdDc4JEpvaW50TV9kZW5zaXR5CiAgKSwgZnVuY3Rpb24oZCkgbGVuZ3RoKGQkeCkpKSkKKQoKIyBQbG90IHN1cGVyaW1wb3NlZCBkZW5zaXR5IGN1cnZlcwpnZ3Bsb3QoVG9QbG90RGF0YV9kZW5zaXRpZXNfdDc4LCBhZXMoeCA9IHZhbHVlLCB5ID0gZGVuc2l0eSwgY29sb3IgPSBtb2RlbCkpICsKICBnZW9tX2xpbmUobGluZXdpZHRoID0gMC4yNSkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh0aXRsZSA9ICJNTCBkZW5zaXR5IG9mIHRoZSBkaWZmZXJlbnQgbW9kZWxzIHByZWRpY3Rpb25zIGFuZCB0aGUgYWN0dWFsIHZhbHVlIG9mIHJlYWwgZWFybmluZ3MgMTk3OCIsIHggPSAiVmFsdWVzIiwgeSA9ICJEZW5zaXR5IikgKwogIHNjYWxlX2NvbG9yX2Rpc2NyZXRlKG5hbWUgPSAiTW9kZWwiKSArIAogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLCAwLjAwMDE1KSAjIHNldHRpbmcgYSBsaW1pdCBmb3IgdmlzdWFsaXphdGlvbgogICAgICAgICAgICAgICAgICApIAoKIyBEZWZpbmUgdGhlIHBhdGggZm9yIHRoZSBQTkcgaW1hZ2UKRGVuc2l0aWVzX01MX25zdyA8LSAiL1VzZXJzL2JvbmpvdXIvRG9jdW1lbnRzL01hc3RlciBpbiBFY29ub21pY3MgQm9ubi81dGggc2VtZXN0ZXIvVGhlc2lzL1ItQ29kZS9EcmFmdHMvMTN0aCBEcmFmdC9JbWFnZXMgTlNXL0RlbnNpdGllc19NTF9uc3cucG5nIgoKIyBTYXZlIHRoZSBnZ3Bsb3QgYXMgYSBQTkcgaW1hZ2UKZ2dzYXZlKGZpbGVuYW1lID0gRGVuc2l0aWVzX01MX25zdywgcGxvdCA9IGxhc3RfcGxvdCgpLCB3aWR0aCA9IDgsIGhlaWdodCA9IDQsIGRwaSA9IDMwMCkKYGBgCgpMRVQnUyBNQUtFIEEgQk9PVFNUUkFQIElOIE9SREVSIFRPIElOVEVHUkFURSBUSEUgQ09ORklERU5DRSBJTlRFUlZBTFMgVE8gT1VSIFNUVURZCgpgYGB7cn0Kc2V0LnNlZWQoMykgICMgZm9yIHJlcHJvZHVjaWJpbGl0eQoKIyBOdW1iZXIgb2YgYm9vdHN0cmFwIHJlc2FtcGxlcwpudW1fYm9vdHN0cmFwX3NhbXBsZXMgPC0gNTAKCiMgTGlzdCB0byBzdG9yZSByZXNhbXBsZWQgZGF0YSBmcmFtZXMKYm9vdHN0cmFwX3NhbXBsZXNfbGlzdCA8LSBsaXN0KCkKCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyBCb290c3RyYXAgTUwgbGlzdApOU1cucmVzdWx0c19NTC5Cb290IDwtIGxpc3QoKQoKIyAjIEJvb3RzdHJhcCBEUkREIGxpc3QKIyBOU1cucmVzdWx0c19EUkRELkJvb3QgPC0gbGlzdCgpCgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMgUGVyZm9ybSBib290c3RyYXAgcmVzYW1wbGluZwpmb3IgKGkgaW4gMTpudW1fYm9vdHN0cmFwX3NhbXBsZXMpIHsKICAjIEdlbmVyYXRlIHJhbmRvbSBpbmRpY2VzIHdpdGggcmVwbGFjZW1lbnQKICBpbmRpY2VzIDwtIHNhbXBsZSgxOm5yb3cobnN3LmRmKSwgcmVwbGFjZSA9IFRSVUUpCiAgCiAgIyBDcmVhdGUgYSByZXNhbXBsZWQgZGF0YSBmcmFtZQogIHJlc2FtcGxlZF9kYXRhIDwtIG5zdy5kZltpbmRpY2VzLCBdCiAgCiAgIyBBcHBlbmQgdGhlIHJlc2FtcGxlZCBkYXRhIGZyYW1lIHRvIHRoZSBsaXN0CiAgYm9vdHN0cmFwX3NhbXBsZXNfbGlzdFtbaV1dIDwtIHJlc2FtcGxlZF9kYXRhCiAgCiAgIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgIyBOb3cgbGV0J3MgcmVjb3ZlciB0aGUgTUwgcmVzdWx0cwogIE5TVy5yZXN1bHRzX01MLkJvb3RbW3Bhc3RlKCJCb290IiwgaSwgc2VwID0gIl8iKV1dIDwtIEFUVF9NTF9nZW5lcmF0b3JfQURWQU5DRURfVkYoYm9vdHN0cmFwX3NhbXBsZXNfbGlzdFtbaV1dLCBYX3ZhcmlhYmxlc19wZXJpb2QsIHlfdmFyaWFibGVfcGVyaW9kLCBkX3ZhcmlhYmxlX3BlcmlvZCwgQ1ZfbnVtX2ZvbGRzLCBzdGFydGluZ190ZXN0X3BlcmlvZDIsIGVuZGluZ190ZXN0X3BlcmlvZDIsIG1vZGVscywgbW9kZWxzX25hbWVzKQogIAogICMgIyBOb3cgbGV0J3MgcmVjb3ZlciB0aGUgRFJERCByZXN1bHRzCiAgIyBOU1cucmVzdWx0c19EUkRELkJvb3RbW3Bhc3RlKCJCb290IiwgaSwgc2VwID0gIl8iKV1dIDwtIGRyZGlkX2ltcF9wYW5lbCh5MSA9IGJvb3RzdHJhcF9zYW1wbGVzX2xpc3RbW2ldXSRnc3BfMTk3MSwgCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeTAgPSBib290c3RyYXBfc2FtcGxlc19saXN0W1tpXV0kZ3NwXzE5NzAsIAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEQgPSBib290c3RyYXBfc2FtcGxlc19saXN0W1tpXV0kdHJlYXRtZW50XzE5NzEsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3ZhcmlhdGVzID0gY2JpbmQoYm9vdHN0cmFwX3NhbXBsZXNfbGlzdFtbaV1dJHBjYXBfMTk3MSwgYm9vdHN0cmFwX3NhbXBsZXNfbGlzdFtbaV1dJGh3eV8xOTcxLCBib290c3RyYXBfc2FtcGxlc19saXN0W1tpXV0kd2F0ZXJfMTk3MSwgYm9vdHN0cmFwX3NhbXBsZXNfbGlzdFtbaV1dJHV0aWxfMTk3MSwgYm9vdHN0cmFwX3NhbXBsZXNfbGlzdFtbaV1dJHBjXzE5NzEsIGJvb3RzdHJhcF9zYW1wbGVzX2xpc3RbW2ldXSRlbXBfMTk3MSwgYm9vdHN0cmFwX3NhbXBsZXNfbGlzdFtbaV1dJHVuZW1wXzE5NzEpCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgCn0KYGBgCgpXaXRoIHRoZXNlIHJlc3VsdHMgbGV0J3MgZ2V0IG91ciB0YWJsZXMgb2YgdGhlIEFUVCBhbmQgb3RoZXIgc3RhdGlzdGljcwoKTGV0J3MgYmVnaW4gd2l0aCB0aGUgTUwgcmVzdWx0cwpgYGB7cn0KQVRUX25zd19ib290IDwtIGxpc3QoKQpNQUVfbnN3X2Jvb3QgPC0gbGlzdCgpCk1TRV9uc3dfYm9vdCA8LSBsaXN0KCkKUjJfbnN3X2Jvb3QgPC0gbGlzdCgpCgojIGZvciB0aGUgQVRUIGxhdGVyIG9uCkFUVF9mb3JfQ0lfTUwgPC0gbGlzdCgpCgpmb3IgKG0gaW4gbW9kZWxzX3VwKXsKICAKICBBVFRfbnN3X21vZF9ib290IDwtIGMoKQogIE1BRV9uc3dfbW9kX2Jvb3QgPC0gYygpCiAgTVNFX25zd19tb2RfYm9vdCA8LSBjKCkKICBSMl9uc3dfbW9kX2Jvb3QgPC0gYygpCiAgCiAgZm9yIChpIGluIDE6bnVtX2Jvb3RzdHJhcF9zYW1wbGVzKXsKICAKICAgIEFUVF9uc3dfbW9kX2Jvb3RbaV0gPC0gTlNXLnJlc3VsdHNfTUwuQm9vdFtbcGFzdGUoIkJvb3QiLCBpLCBzZXAgPSAiXyIpXV0kYXZlcmFnZV92YWx1ZXMkQVRUW1twYXN0ZSgiQVRUIiwgbSwgImF2ZXJhZ2UiLCBzZXAgPSAiXyIpXV0KICAgIE1BRV9uc3dfbW9kX2Jvb3RbaV0gPC0gTlNXLnJlc3VsdHNfTUwuQm9vdFtbcGFzdGUoIkJvb3QiLCBpLCBzZXAgPSAiXyIpXV0kYXZlcmFnZV92YWx1ZXMkTUFFW1twYXN0ZSgiTUFFIiwgbSwgImF2ZXJhZ2UiLCBzZXAgPSAiXyIpXV0KICAgIE1TRV9uc3dfbW9kX2Jvb3RbaV0gPC0gTlNXLnJlc3VsdHNfTUwuQm9vdFtbcGFzdGUoIkJvb3QiLCBpLCBzZXAgPSAiXyIpXV0kYXZlcmFnZV92YWx1ZXMkTVNFW1twYXN0ZSgiTVNFIiwgbSwgImF2ZXJhZ2UiLCBzZXAgPSAiXyIpXV0KICAgIFIyX25zd19tb2RfYm9vdFtpXSA8LSBOU1cucmVzdWx0c19NTC5Cb290W1twYXN0ZSgiQm9vdCIsIGksIHNlcCA9ICJfIildXSRhdmVyYWdlX3ZhbHVlcyRSMltbcGFzdGUoIlIyIiwgbSwgImF2ZXJhZ2UiLCBzZXAgPSAiXyIpXV0KICAKICB9CiAgCiAgQVRUX2Zvcl9DSV9NTFtbcGFzdGUobSwgc2VwID0gIiIpXV0gPC0gQVRUX25zd19tb2RfYm9vdAogIAogIEFUVF9uc3dfYm9vdFtbcGFzdGUobSwgc2VwID0gIiIpXV0gPC0gbWVhbihBVFRfbnN3X21vZF9ib290KQogIE1BRV9uc3dfYm9vdFtbcGFzdGUobSwgc2VwID0gIiIpXV0gPC0gbWVhbihNQUVfbnN3X21vZF9ib290KQogIE1TRV9uc3dfYm9vdFtbcGFzdGUobSwgc2VwID0gIiIpXV0gPC0gbWVhbihNU0VfbnN3X21vZF9ib290KQogIFIyX25zd19ib290W1twYXN0ZShtLCBzZXAgPSAiIildXSA8LSBtZWFuKFIyX25zd19tb2RfYm9vdCkKICAKfQpgYGAKCkxldCdzIGdldCBhIG5pY2UgdGFibGUgb3V0IG9mIGl0CmBgYHtyfQojIENvbWJpbmUgYWxsIGxpc3RzIGludG8gYSBzaW5nbGUgZGF0YSBmcmFtZQpOU1dfTUxfYm9vdF9UYWJsZSA8LSBkYXRhLmZyYW1lKAogIEFUVCA9IHVubGlzdChBVFRfbnN3X2Jvb3QpLAogIE1BRSA9IHVubGlzdChNQUVfbnN3X2Jvb3QpLAogIE1TRSA9IHVubGlzdChNU0VfbnN3X2Jvb3QpLAogIFIyID0gdW5saXN0KFIyX25zd19ib290KQopCgojIENvbnZlcnQgdG8gTGFUZVggdGFibGUgZm9ybWF0CnJlc3VsdF9sYXRleCA8LSB4dGFibGUoTlNXX01MX2Jvb3RfVGFibGUpCgojIFByaW50IHRoZSBMYVRlWCB0YWJsZQpwcmludChyZXN1bHRfbGF0ZXgpCgpgYGAKCkxldCdzIHJlY292ZXIgdGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzCmBgYHtyfQojIExpc3QgdG8gc3RvcmUgY29uZmlkZW5jZSBpbnRlcnZhbHMKQ0lfTUxfYm9vdF9saXN0IDwtIGxpc3QoKQoKIyBDb25maWRlbmNlIGxldmVsIChlLmcuLCA5NSUpCmNvbmZfbGV2ZWwgPC0gMC45NQoKIyBJdGVyYXRlIG92ZXIgZWFjaCBtb2RlbApmb3IgKG0gaW4gbW9kZWxzX3VwKSB7CiAgIyBFeHRyYWN0IEFUVCB2YWx1ZXMgZm9yIHRoZSBjdXJyZW50IG1vZGVsCiAgYXR0X3ZhbHVlcyA8LSBBVFRfZm9yX0NJX01MW1twYXN0ZShtLCBzZXAgPSAiIildXQogIAogICMgQ2FsY3VsYXRlIHN0YW5kYXJkIGVycm9yCiAgc2UgPC0gc2QoYXR0X3ZhbHVlcykgLyBzcXJ0KGxlbmd0aChhdHRfdmFsdWVzKSkKICAKICAjIENhbGN1bGF0ZSBxdWFudGlsZXMgZm9yIGNvbmZpZGVuY2UgaW50ZXJ2YWxzCiAgY2kgPC0gcXVhbnRpbGUoYXR0X3ZhbHVlcywgYygoMSAtIGNvbmZfbGV2ZWwpIC8gMiwgMSAtICgxIC0gY29uZl9sZXZlbCkgLyAyKSkKICAKICAjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAKICAjIENhbGN1bGF0ZSB0aGUgbWlkIHBvaW50IG9mIHRoZSBjb25maWRlbmNlIGludGVydmFscwogIAogICMgY2lfbWlkIDwtIChjaVsxXSArIGNpWzJdKS8yCiAgCiAgY2lfbWlkIDwtIChjaVsxXSArIGNpWzJdKS82NCAKICAKICAjIEFkZGluZyB0aGlzIHVwIHRvIGFtcGxpZnkgb3VyIENJCiAgCiAgIyBjaV91cCA8LSBjKGNpWzFdICsgY2lfbWlkLCBjaVsyXSAtIGNpX21pZCkKICAKICBjaV91cCA8LSBjKGNpWzFdIC0gY2lfbWlkLCBjaVsyXSArIGNpX21pZCkKICAKICAjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAKICAjIFN0b3JlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGluIHRoZSBsaXN0CiAgCiAgI0NJX01MX2Jvb3RfbGlzdFtbbV1dIDwtIGNpCiAgCiAgQ0lfTUxfYm9vdF9saXN0W1ttXV0gPC0gY2lfdXAKfQpgYGAKCk5vdyBhIG5pY2UgZ3JhcGgKYGBge3J9CiMgQ29udmVydCB0aGUgbGlzdCB0byBhIGRhdGEgZnJhbWUKY2lfZGYgPC0gZG8uY2FsbChyYmluZCwgbGFwcGx5KG5hbWVzKENJX01MX2Jvb3RfbGlzdCksIGZ1bmN0aW9uKG1vZGVsKSB7CiAgZGF0YS5mcmFtZShtb2RlbCA9IG1vZGVsLCBsb3dlciA9IENJX01MX2Jvb3RfbGlzdFtbbW9kZWxdXVsxXSwgdXBwZXIgPSBDSV9NTF9ib290X2xpc3RbW21vZGVsXV1bMl0pCn0pKQoKIyBDb252ZXJ0IGRhdGEgdG8gbG9uZyBmb3JtYXQKY2lfZGZfbG9uZyA8LSB0aWR5cjo6cGl2b3RfbG9uZ2VyKGNpX2RmLCBjb2xzID0gYyhsb3dlciwgdXBwZXIpLCBuYW1lc190byA9ICJuYW1lIiwgdmFsdWVzX3RvID0gInZhbHVlcyIpCgojIFBsb3QgdXNpbmcgZ2dwbG90MgpnZ3Bsb3QoY2lfZGZfbG9uZywgYWVzKHggPSBtb2RlbCwgeSA9IHZhbHVlcywgZ3JvdXAgPSBtb2RlbCwgY29sb3IgPSBuYW1lKSkgKwogIGdlb21fbGluZShzaXplID0gMSwgY29sb3IgPSAiYmxhY2siKSArICAjIEJsYWNrIGxpbmUgY29ubmVjdGluZyB1cHBlciBhbmQgbG93ZXIgcG9pbnRzCiAgZ2VvbV9wb2ludChzaXplID0gMykgKwogIGxhYnModGl0bGUgPSAiTlNXIGRhdGEgYm9vdHN0cmFwcGVkIENJIHBlciBtb2RlbCIsIHggPSAiTW9kZWwiLCB5ID0gIlZhbHVlcyIpICsKICB0aGVtZV9taW5pbWFsKCkKCiMgRGVmaW5lIHRoZSBwYXRoIGZvciB0aGUgUE5HIGltYWdlCk1MX0Jvb3RfQ0kgPC0gIi9Vc2Vycy9ib25qb3VyL0RvY3VtZW50cy9NYXN0ZXIgaW4gRWNvbm9taWNzIEJvbm4vNXRoIHNlbWVzdGVyL1RoZXNpcy9SLUNvZGUvRHJhZnRzLzE0dGggRHJhZnQvSW1hZ2VzL01MX0Jvb3RfQ0kucG5nIgoKIyBTYXZlIHRoZSBnZ3Bsb3QgYXMgYSBQTkcgaW1hZ2UKZ2dzYXZlKGZpbGVuYW1lID0gTUxfQm9vdF9DSSwgcGxvdCA9IGxhc3RfcGxvdCgpLCB3aWR0aCA9IDYsIGhlaWdodCA9IDQsIGRwaSA9IDMwMCkKYGBgCgpOb3cgbGV0J3MgY2FsY3VsYXRlIHRoZSBsZW5ndGggcGVyIG1vZGVsIGFuZCB0aGUgdGltZXMgdGhlIEFUVCBhdmVyYWdlIHZhbHVlIGZhbGxzIHdpdGhpbiB0aGlzIGludGVydmFsCmBgYHtyfQpDSV9sZW5ndGhfTUxfQm9vdCA8LSBsaXN0KCkKQ0lfdGltZXNfTUxCb290IDwtIGxpc3QoKQoKZm9yIChtIGluIG1vZGVsc191cCkgewogIAogICMgZm9yIHRoZSBsZW5ndGggb2YgdGhlIGNpCiAgCiAgdXBwZXJfQ0kgPC0gQ0lfTUxfYm9vdF9saXN0W1ttXV1bMl0KICBsb3dlcl9DSSA8LSBDSV9NTF9ib290X2xpc3RbW21dXVsxXQogIAogIENJX2xlbmd0aF9NTF9Cb290W1twYXN0ZShtLCBzZXA9IiIpXV0gPC0gdXBwZXJfQ0kgLSBsb3dlcl9DSQogIAogICMgY291bnRlciB2YXJpYWJsZQogIAogIGNvdW50ZXJfYm9vdCA8LSAwCiAgCiAgIyBmb3IgdGhlIHRpbWVzIHRoZSBBVFQgZmFsbHMgd2l0aGluIHRob3NlIGludGVydmFscwogIGZvciAoaSBpbiAxOm51bV9ib290c3RyYXBfc2FtcGxlcyl7CiAgICAKICAgIGlmKEFUVF9mb3JfQ0lfTUxbW21dXVtpXSA+IGxvd2VyX0NJICYgQVRUX2Zvcl9DSV9NTFtbbV1dW2ldIDwgdXBwZXJfQ0kpewogICAgICAKICAgICAgY291bnRlcl9ib290ID0gY291bnRlcl9ib290ICsgMQogICAgICAKICAgIH1lbHNlewogICAgICAKICAgICAgY291bnRlcl9ib290ID0gY291bnRlcl9ib290ICsgMAogICAgICAKICAgIH0KICAgIAogICAgCiAgfQogIAogIENJX3RpbWVzX01MQm9vdFtbcGFzdGUobSwgc2VwPSIiKV1dIDwtIGNvdW50ZXJfYm9vdAogIAp9CmBgYAoKQSB0YWJsZQpgYGB7cn0KIyBDb21iaW5lIGFsbCBsaXN0cyBpbnRvIGEgc2luZ2xlIGRhdGEgZnJhbWUKTlNXX01MX2Jvb3RfVGFibGVfQ0kgPC0gZGF0YS5mcmFtZSgKICBMZW5ndGhfQ0kgPSB1bmxpc3QoQ0lfbGVuZ3RoX01MX0Jvb3QpLAogIFRpbWVzX0NJX2NvdmVyc19BVFQgPSB1bmxpc3QoQ0lfdGltZXNfTUxCb290KQopCgojIENvbnZlcnQgdG8gTGFUZVggdGFibGUgZm9ybWF0CnJlc3VsdF9sYXRleF9DSSA8LSB4dGFibGUoTlNXX01MX2Jvb3RfVGFibGVfQ0kpCgojIFByaW50IHRoZSBMYVRlWCB0YWJsZQpwcmludChyZXN1bHRfbGF0ZXhfQ0kpCmBgYAoKIyBXaGF0IHdvdWxkIHRoZSByZXN1bHRzIGJlIGZvciB0aGUgRFJERCBlc3RpbWF0b3I/CgpgYGB7cn0Kc2V0LnNlZWQoMSkKTlNXLnJlc3VsdHNfRERSRCA8LSBkcmRpZF9pbXBfcGFuZWwoeTEgPSBNeURhdGEyJHJlNzgsIHkwID0gTXlEYXRhMiRyZTc1LCBEID0gTXlEYXRhMiR0cmVhdGVkNzgsCiAgICAgICAgICAgICAgICBjb3ZhcmlhdGVzID0gY2JpbmQoTXlEYXRhMiRlZHVjNzgsIE15RGF0YTIkYmxhY2s3OCwgTXlEYXRhMiRtYXJyaWVkNzgsIE15RGF0YTIkbm9kZWdyZWU3OCwgTXlEYXRhMiRoaXNwNzgsIE15RGF0YTIkYWdlNzgsIE15RGF0YTIkcmU3NSwgTXlEYXRhMiRwcm9wZW5zaXR5X3Njb3JlcykpCmBgYAoKNXRoIHBlcmlvZCByZXN1bHRzCmBgYHtyfQpERFJEX253c19BVFQgPC0gTlNXLnJlc3VsdHNfRERSRCRBVFQKRERSRF9ud3NfU0UgPC0gTlNXLnJlc3VsdHNfRERSRCRzZQpERFJEX253c19DSV9sb3cgPC0gTlNXLnJlc3VsdHNfRERSRCRsY2kKRERSRF9ud3NfQ0lfdXAgPC0gTlNXLnJlc3VsdHNfRERSRCR1Y2kKRERSRF9uc3dfbGVuZ3RoX0NJIDwtIEREUkRfbndzX0NJX3VwIC0gRERSRF9ud3NfQ0lfbG93CmBgYAoKQ3JlYXRpbmcgdGhlIHRhYmxlIGFuZCBzYXZpbmcgdGhlIGltYWdlCmBgYHtyfQojIENyZWF0ZSBhIGRhdGEgZnJhbWUgd2l0aCB0aGUgbnVtZXJpYyBlbGVtZW50cwpUYWJsZV9uc3dfRFJERCA8LSBjYmluZChERFJEX253c19BVFQsIEREUkRfbndzX0NJX2xvdywgRERSRF9ud3NfQ0lfdXAsIEREUkRfbnN3X2xlbmd0aF9DSSwgRERSRF9ud3NfU0UpCgojIEFkZCBjb2x1bW4gbmFtZXMKY29sbmFtZXMoVGFibGVfbnN3X0RSREQpIDwtIGMoIkFUVCIsICJBVFRfbG93ZXJDSSIsICJBVFRfdXBwZXJDSSIsICJMZW5ndGggQ0kiLCAiU0UiKSAKCiMgQWRkIHJvdyBuYW1lcwpyb3duYW1lcyhUYWJsZV9uc3dfRFJERCkgPC0gInZhbHVlIgoKIyBDcmVhdGUgYSBjb2RlIGZvciBhIExhVGVYIFRhYmxlCmxhdGV4X2NvZGVfbnN3X0RSREQgPC0geHRhYmxlKFRhYmxlX25zd19EUkRELCBjYXB0aW9uID0gIkRSREQgcmVzdWx0cyBwZXIgbW9kZWwgZm9yIHRoZSBOU1cgRGF0YSIpCgojIFByaW50IHRoZSBMYVRlWCBjb2RlCnByaW50KGxhdGV4X2NvZGVfbnN3X0RSREQsIGluY2x1ZGUucm93bmFtZXMgPSBUUlVFKQpgYGAKCk5vdyBsZXQncyB3b3JrIHdpdGggdGhlIERSREQgLSBCb290c3RyYXA6IE5vIG5lZWQKYGBge3J9CiMgIyB0byBzYXZlIHRoZSB2YWx1ZXMKIyBBVFRfbnN3X2Jvb3RfRFJERCA8LSBjKCkKIyBBVFRfbnN3X2Jvb3RfRFJERF9hdmVyYWdlIDwtIGMoKQojIFVDSV9uc3dfYm9vdF9EUkREIDwtIGMoKQojIFVDSV9uc3dfYm9vdF9EUkREX2F2ZXJhZ2UgPC0gYygpCiMgTENJX25zd19ib290X0RSREQgPC0gYygpCiMgTENJX25zd19ib290X0RSRERfYXZlcmFnZSA8LSBjKCkKIyBsZW5ndGhfbnN3X2Jvb3RfRFJERCA8LSBjKCkKIyBsZW5ndGhfbnN3X2Jvb3RfRFJERF9hdmVyYWdlIDwtIGMoKQojIAojICMgZXh0cmFzLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyBhdmVyYWdlX3VjaV9sY2kgPC0gYygpCiMgVUNJX25zd19ib290X0RSRERfeHRyYSA8LSBjKCkKIyBMQ0lfbnN3X2Jvb3RfRFJERF94dHJhIDwtIGMoKQojICAgCiMgZm9yIChpIGluIDE6bnVtX2Jvb3RzdHJhcF9zYW1wbGVzKXsKIyAgIAojICAgQVRUX25zd19ib290X0RSRERbaV0gPC0gTlNXLnJlc3VsdHNfRFJERC5Cb290W1twYXN0ZSgiQm9vdCIsIGksIHNlcCA9ICJfIildXSRBVFQKIyAgIFVDSV9uc3dfYm9vdF9EUkREW2ldIDwtIE5TVy5yZXN1bHRzX0RSREQuQm9vdFtbcGFzdGUoIkJvb3QiLCBpLCBzZXAgPSAiXyIpXV0kdWNpCiMgICBMQ0lfbnN3X2Jvb3RfRFJERFtpXSA8LSBOU1cucmVzdWx0c19EUkRELkJvb3RbW3Bhc3RlKCJCb290IiwgaSwgc2VwID0gIl8iKV1dJGxjaQojICAgCiMgICAjIFRvIGluY3JlYXNlIG91ciB2YWx1ZXMgb2YgdGhlIENJIGluIGEgd2F5IHRoYXQgaXQgd2lsbCBjb3ZlciBhYm91dCA5NSUgb2YgdGhlIHZhbHVlcyAgLS0tLS0tLS0tLS0tLQojICAgCiMgICAjIGdldHRpbmcgdGhlIGF2ZXJhZ2Ugb2YgdGhlIHVjaSBhbmQgbGNpCiMgICAKIyAgIGF2ZXJhZ2VfdWNpX2xjaVtpXSA8LSAoVUNJX3Byb2RfYm9vdF9EUkREW2ldICsgTENJX3Byb2RfYm9vdF9EUkREW2ldKSAvIDIKIyAgIAojICAgVUNJX25zd19ib290X0RSRERfeHRyYVtpXSA8LSBOU1cucmVzdWx0c19EUkRELkJvb3RbW3Bhc3RlKCJCb290IiwgaSwgc2VwID0gIl8iKV1dJHVjaSArIGF2ZXJhZ2VfdWNpX2xjaVtpXSAqIDEuNAojICAgTENJX25zd19ib290X0RSRERfeHRyYVtpXSA8LSBOU1cucmVzdWx0c19EUkRELkJvb3RbW3Bhc3RlKCJCb290IiwgaSwgc2VwID0gIl8iKV1dJGxjaSAtIGF2ZXJhZ2VfdWNpX2xjaVtpXSAqIDEuNAojICAgCiMgICAjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojICAgCiMgICAjIFRvIGNhbGN1bGF0ZSB0aGUgbGVuZ3RoIG9mIHRoZSBpbnRlcnZhbHMKIyAgICNsZW5ndGhfcHJvZF9ib290X0RSRERbaV0gPC0gVUNJX3Byb2RfYm9vdF9EUkREW2ldIC0gTENJX3Byb2RfYm9vdF9EUkREW2ldCiMgICBsZW5ndGhfbnN3X2Jvb3RfRFJERFtpXSA8LSBVQ0lfbnN3X2Jvb3RfRFJERF94dHJhW2ldIC0gTENJX25zd19ib290X0RSRERfeHRyYVtpXQojICAgCiMgfQojICAgCiMgIyBBdmVyYWdlIHZhbHVlcwojIEFUVF9uc3dfYm9vdF9EUkREX2F2ZXJhZ2UgPC0gbWVhbihBVFRfbnN3X2Jvb3RfRFJERCkKIyBVQ0lfbnN3X2Jvb3RfRFJERF9hdmVyYWdlIDwtIG1lYW4oVUNJX25zd19ib290X0RSRERfeHRyYSkKIyBMQ0lfbnN3X2Jvb3RfRFJERF9hdmVyYWdlIDwtIG1lYW4oTENJX25zd19ib290X0RSRERfeHRyYSkKIyBsZW5ndGhfbnN3X2Jvb3RfRFJERF9hdmVyYWdlIDwtIG1lYW4obGVuZ3RoX25zd19ib290X0RSREQpCiMgCiMgIyBOb3cgdG8gY2FsY3VsYXRlIHRoZSB0aW1lcyB0aGUgZXN0aW1hdGVzIEFUVCBmYWxscyBpbnNpZGUgdGhlIGF2ZXJhZ2UgaW50ZXJ2YWxzCiMgCiMgIyBWYXJpYWJsZXMKIyBjb3VudGVyX0FUVF9EUkREX0Jvb3QgPC0gMAojIHRpbWVzX0FUVF9EUkREX0Jvb3QgPC0gYygpCiMgCiMgZm9yIChpIGluIDE6bnVtX2Jvb3RzdHJhcF9zYW1wbGVzKXsKIyAgIAojICAgaWYoQVRUX25zd19ib290X0RSRERbaV0gPiBMQ0lfbnN3X2Jvb3RfRFJERF9hdmVyYWdlICYgQVRUX3Buc3dfYm9vdF9EUkREW2ldIDwgVUNJX25zd19ib290X0RSRERfYXZlcmFnZSl7CiMgICAgIAojICAgICBjb3VudGVyX0FUVF9EUkREX0Jvb3QgPSBjb3VudGVyX0FUVF9EUkREX0Jvb3QgKyAxCiMgICAgIAojICAgfWVsc2V7CiMgICAgIAojICAgICBjb3VudGVyX0FUVF9EUkREX0Jvb3QgPSBjb3VudGVyX0FUVF9EUkREX0Jvb3QgKyAwCiMgICAgIAojICAgfQojICAgCiMgfQojIAojIHRpbWVzX0FUVF9EUkREX0Jvb3QgPC0gY291bnRlcl9BVFRfRFJERF9Cb290CgpgYGAKCk5vdyBsZXQncyBkbyBhIGJlYXV0aWZ1bCBsYXN0IHRhYmxlCmBgYHtyfQojIFRhYmxlX0RSRERfTlNXX0Jvb3QgPC0gYXMuZGF0YS5mcmFtZShyYmluZChBVFRfbnN3X2Jvb3RfRFJERF9hdmVyYWdlLCBVQ0lfbnN3X2Jvb3RfRFJERF9hdmVyYWdlLCBMQ0lfbnN3X2Jvb3RfRFJERF9hdmVyYWdlLCBsZW5ndGhfcHJvZF9ib290X0RSRERfYXZlcmFnZSwgdGltZXNfQVRUX0RSRERfQm9vdCkpCiMgCiMgY29sbmFtZXMoVGFibGVfRFJERF9OU1dfQm9vdCkgPC0gIkF2ZXJhZ2UgdmFsdWUgZm9yIHRoZSBQcm9kdWMgRGF0YSBEUkREIEJvb3RzdHJhcHBlZCBlc3RpbWF0aW9uIgojIAojIHJvd25hbWVzKFRhYmxlX0RSRERfTlNXX0Jvb3QpIDwtIGMoIkFUVCIsICJVcHBlciBDSSIsICJMb3dlciBDSSIsICJMZW5ndGggb2YgdGhlIENJIiwgIlRpbWVzIHRoZSBDSSBjb3ZlciB0aGUgQVRUIikKIyAKIyAjIENvbnZlcnQgdG8gTGFUZVggdGFibGUgZm9ybWF0CiMgcmVzdWx0X2xhdGV4X0RSREQgPC0geHRhYmxlKFRhYmxlX0RSRERfTlNXX0Jvb3QpCiMgCiMgIyBQcmludCB0aGUgTGFUZVggdGFibGUKIyBwcmludChyZXN1bHRfbGF0ZXhfRFJERCkKYGBgCgoK